home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / lang / tcl / tclx7.5a- / tclx7 / usr / local / tkX / 4.1a-a2 / tk.tlib < prev    next >
Encoding:
Text File  |  1995-11-14  |  128.3 KB  |  4,805 lines

  1. #@package: library/optMenu tk_optionMenu
  2.  
  3. # optMenu.tcl --
  4. #
  5. # This file defines the procedure tk_optionMenu, which creates
  6. # an option button and its associated menu.
  7. #
  8. # @(#) optMenu.tcl 1.7 95/10/04 15:00:18
  9. #
  10. # Copyright (c) 1994 The Regents of the University of California.
  11. # Copyright (c) 1994 Sun Microsystems, Inc.
  12. #
  13. # See the file "license.terms" for information on usage and redistribution
  14. # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  15. #
  16.  
  17. # tk_optionMenu --
  18. # This procedure creates an option button named $w and an associated
  19. # menu.  Together they provide the functionality of Motif option menus:
  20. # they can be used to select one of many values, and the current value
  21. # appears in the global variable varName, as well as in the text of
  22. # the option menubutton.  The name of the menu is returned as the
  23. # procedure's result, so that the caller can use it to change configuration
  24. # options on the menu or otherwise manipulate it.
  25. #
  26. # Arguments:
  27. # w -            The name to use for the menubutton.
  28. # varName -        Global variable to hold the currently selected value.
  29. # firstValue -        First of legal values for option (must be >= 1).
  30. # args -        Any number of additional values.
  31.  
  32. proc tk_optionMenu {w varName firstValue args} {
  33.     upvar #0 $varName var
  34.  
  35.     if ![info exists var] {
  36.     set var $firstValue
  37.     }
  38.     menubutton $w -textvariable $varName -indicatoron 1 -menu $w.menu \
  39.         -relief raised -bd 2 -padx 4p -pady 4p -highlightthickness 2 \
  40.         -anchor c
  41.     menu $w.menu -tearoff 0
  42.     $w.menu add command -label $firstValue \
  43.         -command [list set $varName $firstValue]
  44.     foreach i $args {
  45.     $w.menu add command -label $i -command [list set $varName $i]
  46.     }
  47.     return $w.menu
  48. }
  49. #@package: library/scale tkScaleControlPress tkScaleActivate tkScaleEndDrag tkScaleButtonDown tkScaleButton2Down tkScaleIncrement tkScaleDrag
  50.  
  51. # scale.tcl --
  52. #
  53. # This file defines the default bindings for Tk scale widgets and provides
  54. # procedures that help in implementing the bindings.
  55. #
  56. # @(#) scale.tcl 1.10 95/09/26 16:45:00
  57. #
  58. # Copyright (c) 1994 The Regents of the University of California.
  59. # Copyright (c) 1994-1995 Sun Microsystems, Inc.
  60. #
  61. # See the file "license.terms" for information on usage and redistribution
  62. # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  63. #
  64.  
  65. #-------------------------------------------------------------------------
  66. # The code below creates the default class bindings for entries.
  67. #-------------------------------------------------------------------------
  68.  
  69. # Standard Motif bindings:
  70.  
  71. bind Scale <Enter> {
  72.     if $tk_strictMotif {
  73.     set tkPriv(activeBg) [%W cget -activebackground]
  74.     %W config -activebackground [%W cget -background]
  75.     }
  76.     tkScaleActivate %W %x %y
  77. }
  78. bind Scale <Motion> {
  79.     tkScaleActivate %W %x %y
  80. }
  81. bind Scale <Leave> {
  82.     if $tk_strictMotif {
  83.     %W config -activebackground $tkPriv(activeBg)
  84.     }
  85.     if {[%W cget -state] == "active"} {
  86.     %W configure -state normal
  87.     }
  88. }
  89. bind Scale <1> {
  90.     tkScaleButtonDown %W %x %y
  91. }
  92. bind Scale <B1-Motion> {
  93.     tkScaleDrag %W %x %y
  94. }
  95. bind Scale <B1-Leave> { }
  96. bind Scale <B1-Enter> { }
  97. bind Scale <ButtonRelease-1> {
  98.     tkCancelRepeat
  99.     tkScaleEndDrag %W
  100.     tkScaleActivate %W %x %y
  101. }
  102. bind Scale <2> {
  103.     tkScaleButton2Down %W %x %y
  104. }
  105. bind Scale <B2-Motion> {
  106.     tkScaleDrag %W %x %y
  107. }
  108. bind Scale <B2-Leave> { }
  109. bind Scale <B2-Enter> { }
  110. bind Scale <ButtonRelease-2> {
  111.     tkCancelRepeat
  112.     tkScaleEndDrag %W
  113.     tkScaleActivate %W %x %y
  114. }
  115. bind Scale <Control-1> {
  116.     tkScaleControlPress %W %x %y
  117. }
  118. bind Scale <Up> {
  119.     tkScaleIncrement %W up little noRepeat
  120. }
  121. bind Scale <Down> {
  122.     tkScaleIncrement %W down little noRepeat
  123. }
  124. bind Scale <Left> {
  125.     tkScaleIncrement %W up little noRepeat
  126. }
  127. bind Scale <Right> {
  128.     tkScaleIncrement %W down little noRepeat
  129. }
  130. bind Scale <Control-Up> {
  131.     tkScaleIncrement %W up big noRepeat
  132. }
  133. bind Scale <Control-Down> {
  134.     tkScaleIncrement %W down big noRepeat
  135. }
  136. bind Scale <Control-Left> {
  137.     tkScaleIncrement %W up big noRepeat
  138. }
  139. bind Scale <Control-Right> {
  140.     tkScaleIncrement %W down big noRepeat
  141. }
  142. bind Scale <Home> {
  143.     %W set [%W cget -from]
  144. }
  145. bind Scale <End> {
  146.     %W set [%W cget -to]
  147. }
  148.  
  149. # tkScaleActivate --
  150. # This procedure is invoked to check a given x-y position in the
  151. # scale and activate the slider if the x-y position falls within
  152. # the slider.
  153. #
  154. # Arguments:
  155. # w -        The scale widget.
  156. # x, y -    Mouse coordinates.
  157.  
  158. proc tkScaleActivate {w x y} {
  159.     global tkPriv
  160.     if {[$w cget -state] == "disabled"} {
  161.     return;
  162.     }
  163.     if {[$w identify $x $y] == "slider"} {
  164.     $w configure -state active
  165.     } else {
  166.     $w configure -state normal
  167.     }
  168. }
  169.  
  170. # tkScaleButtonDown --
  171. # This procedure is invoked when a button is pressed in a scale.  It
  172. # takes different actions depending on where the button was pressed.
  173. #
  174. # Arguments:
  175. # w -        The scale widget.
  176. # x, y -    Mouse coordinates of button press.
  177.  
  178. proc tkScaleButtonDown {w x y} {
  179.     global tkPriv
  180.     set tkPriv(dragging) 0
  181.     set el [$w identify $x $y]
  182.     if {$el == "trough1"} {
  183.     tkScaleIncrement $w up little initial
  184.     } elseif {$el == "trough2"} {
  185.     tkScaleIncrement $w down little initial
  186.     } elseif {$el == "slider"} {
  187.     set tkPriv(dragging) 1
  188.     set tkPriv(initValue) [$w get]
  189.     set coords [$w coords]
  190.     set tkPriv(deltaX) [expr $x - [lindex $coords 0]]
  191.     set tkPriv(deltaY) [expr $y - [lindex $coords 1]]
  192.     $w configure -sliderrelief sunken
  193.     }
  194. }
  195.  
  196. # tkScaleDrag --
  197. # This procedure is called when the mouse is dragged with
  198. # mouse button 1 down.  If the drag started inside the slider
  199. # (i.e. the scale is active) then the scale's value is adjusted
  200. # to reflect the mouse's position.
  201. #
  202. # Arguments:
  203. # w -        The scale widget.
  204. # x, y -    Mouse coordinates.
  205.  
  206. proc tkScaleDrag {w x y} {
  207.     global tkPriv
  208.     if !$tkPriv(dragging) {
  209.     return
  210.     }
  211.     $w set [$w get [expr $x - $tkPriv(deltaX)] \
  212.         [expr $y - $tkPriv(deltaY)]]
  213. }
  214.  
  215. # tkScaleEndDrag --
  216. # This procedure is called to end an interactive drag of the
  217. # slider.  It just marks the drag as over.
  218. #
  219. # Arguments:
  220. # w -        The scale widget.
  221.  
  222. proc tkScaleEndDrag {w} {
  223.     global tkPriv
  224.     set tkPriv(dragging) 0
  225.     $w configure -sliderrelief raised
  226. }
  227.  
  228. # tkScaleIncrement --
  229. # This procedure is invoked to increment the value of a scale and
  230. # to set up auto-repeating of the action if that is desired.  The
  231. # way the value is incremented depends on the "dir" and "big"
  232. # arguments.
  233. #
  234. # Arguments:
  235. # w -        The scale widget.
  236. # dir -        "up" means move value towards -from, "down" means
  237. #        move towards -to.
  238. # big -        Size of increments: "big" or "little".
  239. # repeat -    Whether and how to auto-repeat the action:  "noRepeat"
  240. #        means don't auto-repeat, "initial" means this is the
  241. #        first action in an auto-repeat sequence, and "again"
  242. #        means this is the second repetition or later.
  243.  
  244. proc tkScaleIncrement {w dir big repeat} {
  245.     global tkPriv
  246.     if {$big == "big"} {
  247.     set inc [$w cget -bigincrement]
  248.     if {$inc == 0} {
  249.         set inc [expr abs([$w cget -to] - [$w cget -from])/10.0]
  250.     }
  251.     if {$inc < [$w cget -resolution]} {
  252.         set inc [$w cget -resolution]
  253.     }
  254.     } else {
  255.     set inc [$w cget -resolution]
  256.     }
  257.     if {([$w cget -from] > [$w cget -to]) ^ ($dir == "up")} {
  258.     set inc [expr -$inc]
  259.     }
  260.     $w set [expr [$w get] + $inc]
  261.  
  262.     if {$repeat == "again"} {
  263.     set tkPriv(afterId) [after [$w cget -repeatinterval] \
  264.         tkScaleIncrement $w $dir $big again]
  265.     } elseif {$repeat == "initial"} {
  266.     set delay [$w cget -repeatdelay]
  267.     if {$delay > 0} {
  268.         set tkPriv(afterId) [after $delay \
  269.             tkScaleIncrement $w $dir $big again]
  270.     }
  271.     }
  272. }
  273.  
  274. # tkScaleControlPress --
  275. # This procedure handles button presses that are made with the Control
  276. # key down.  Depending on the mouse position, it adjusts the scale
  277. # value to one end of the range or the other.
  278. #
  279. # Arguments:
  280. # w -        The scale widget.
  281. # x, y -    Mouse coordinates where the button was pressed.
  282.  
  283. proc tkScaleControlPress {w x y} {
  284.     set el [$w identify $x $y]
  285.     if {$el == "trough1"} {
  286.     $w set [$w cget -from]
  287.     } elseif {$el == "trough2"} {
  288.     $w set [$w cget -to]
  289.     }
  290. }
  291.  
  292. # tkScaleButton2Down
  293. # This procedure is invoked when button 2 is pressed over a scale.
  294. # It sets the value to correspond to the mouse position and starts
  295. # a slider drag.
  296. #
  297. # Arguments:
  298. # w -        The scrollbar widget.
  299. # x, y -    Mouse coordinates within the widget.
  300.  
  301. proc tkScaleButton2Down {w x y} {
  302.     global tkPriv
  303.  
  304.     if {[$w cget -state] == "disabled"} {
  305.     return;
  306.     }
  307.     $w configure -state active
  308.     $w set [$w get $x $y]
  309.     set tkPriv(dragging) 1
  310.     set tkPriv(initValue) [$w get]
  311.     set coords "$x $y"
  312.     set tkPriv(deltaX) 0
  313.     set tkPriv(deltaY) 0
  314. }
  315. #@package: library/focus tk_focusPrev tkFocusOK tk_focusNext tk_focusFollowsMouse
  316.  
  317. # focus.tcl --
  318. #
  319. # This file defines several procedures for managing the input
  320. # focus.
  321. #
  322. # @(#) focus.tcl 1.15 95/08/21 09:34:03
  323. #
  324. # Copyright (c) 1994-1995 Sun Microsystems, Inc.
  325. #
  326. # See the file "license.terms" for information on usage and redistribution
  327. # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  328. #
  329.  
  330. # tk_focusNext --
  331. # This procedure returns the name of the next window after "w" in
  332. # "focus order" (the window that should receive the focus next if
  333. # Tab is typed in w).  "Next" is defined by a pre-order search
  334. # of a top-level and its non-top-level descendants, with the stacking
  335. # order determining the order of siblings.  The "-takefocus" options
  336. # on windows determine whether or not they should be skipped.
  337. #
  338. # Arguments:
  339. # w -        Name of a window.
  340.  
  341. proc tk_focusNext w {
  342.     set cur $w
  343.     while 1 {
  344.  
  345.     # Descend to just before the first child of the current widget.
  346.  
  347.     set parent $cur
  348.     set children [winfo children $cur]
  349.     set i -1
  350.  
  351.     # Look for the next sibling that isn't a top-level.
  352.  
  353.     while 1 {
  354.         incr i
  355.         if {$i < [llength $children]} {
  356.         set cur [lindex $children $i]
  357.         if {[winfo toplevel $cur] == $cur} {
  358.             continue
  359.         } else {
  360.             break
  361.         }
  362.         }
  363.  
  364.         # No more siblings, so go to the current widget's parent.
  365.         # If it's a top-level, break out of the loop, otherwise
  366.         # look for its next sibling.
  367.  
  368.         set cur $parent
  369.         if {[winfo toplevel $cur] == $cur} {
  370.         break
  371.         }
  372.         set parent [winfo parent $parent]
  373.         set children [winfo children $parent]
  374.         set i [lsearch -exact $children $cur]
  375.     }
  376.     if {($cur == $w) || [tkFocusOK $cur]} {
  377.         return $cur
  378.     }
  379.     }
  380. }
  381.  
  382. # tk_focusPrev --
  383. # This procedure returns the name of the previous window before "w" in
  384. # "focus order" (the window that should receive the focus next if
  385. # Shift-Tab is typed in w).  "Next" is defined by a pre-order search
  386. # of a top-level and its non-top-level descendants, with the stacking
  387. # order determining the order of siblings.  The "-takefocus" options
  388. # on windows determine whether or not they should be skipped.
  389. #
  390. # Arguments:
  391. # w -        Name of a window.
  392.  
  393. proc tk_focusPrev w {
  394.     set cur $w
  395.     while 1 {
  396.  
  397.     # Collect information about the current window's position
  398.     # among its siblings.  Also, if the window is a top-level,
  399.     # then reposition to just after the last child of the window.
  400.     
  401.     if {[winfo toplevel $cur] == $cur}  {
  402.         set parent $cur
  403.         set children [winfo children $cur]
  404.         set i [llength $children]
  405.     } else {
  406.         set parent [winfo parent $cur]
  407.         set children [winfo children $parent]
  408.         set i [lsearch -exact $children $cur]
  409.     }
  410.  
  411.     # Go to the previous sibling, then descend to its last descendant
  412.     # (highest in stacking order.  While doing this, ignore top-levels
  413.     # and their descendants.  When we run out of descendants, go up
  414.     # one level to the parent.
  415.  
  416.     while {$i > 0} {
  417.         incr i -1
  418.         set cur [lindex $children $i]
  419.         if {[winfo toplevel $cur] == $cur} {
  420.         continue
  421.         }
  422.         set parent $cur
  423.         set children [winfo children $parent]
  424.         set i [llength $children]
  425.     }
  426.     set cur $parent
  427.     if {($cur == $w) || [tkFocusOK $cur]} {
  428.         return $cur
  429.     }
  430.     }
  431. }
  432.  
  433. # tkFocusOK --
  434. #
  435. # This procedure is invoked to decide whether or not to focus on
  436. # a given window.  It returns 1 if it's OK to focus on the window,
  437. # 0 if it's not OK.  The code first checks whether the window is
  438. # viewable.  If not, then it never focuses on the window.  Then it
  439. # checks the -takefocus option for the window and uses it if it's
  440. # set.  If there's no -takefocus option, the procedure checks to
  441. # see if (a) the widget isn't disabled, and (b) it has some key
  442. # bindings.  If all of these are true, then 1 is returned.
  443. #
  444. # Arguments:
  445. # w -        Name of a window.
  446.  
  447. proc tkFocusOK w {
  448.     set code [catch {$w cget -takefocus} value]
  449.     if {($code == 0) && ($value != "")} {
  450.     if {$value == 0} {
  451.         return 0
  452.     } elseif {$value == 1} {
  453.         return [winfo viewable $w]
  454.     } else {
  455.         set value [uplevel #0 $value $w]
  456.         if {$value != ""} {
  457.         return $value
  458.         }
  459.     }
  460.     }
  461.     if {![winfo viewable $w]} {
  462.     return 0
  463.     }
  464.     set code [catch {$w cget -state} value]
  465.     if {($code == 0) && ($value == "disabled")} {
  466.     return 0
  467.     }
  468.     regexp Key|Focus "[bind $w] [bind [winfo class $w]]"
  469. }
  470.  
  471. # tk_focusFollowsMouse --
  472. #
  473. # If this procedure is invoked, Tk will enter "focus-follows-mouse"
  474. # mode, where the focus is always on whatever window contains the
  475. # mouse.  If this procedure isn't invoked, then the user typically
  476. # has to click on a window to give it the focus.
  477. #
  478. # Arguments:
  479. # None.
  480.  
  481. proc tk_focusFollowsMouse {} {
  482.     set old [bind all <Enter>]
  483.     set script {
  484.     if {("%d" == "NotifyAncestor") || ("%d" == "NotifyNonlinear")
  485.         || ("%d" == "NotifyInferior")} {
  486.         focus %W
  487.     }
  488.     }
  489.     if {$old != ""} {
  490.     bind all <Enter> "$old; $script"
  491.     } else {
  492.     bind all <Enter> $script
  493.     }
  494. }
  495. #@package: library/entry tkEntrySeeInsert tkEntryInsert tkEntryKeySelect tkEntrySetCursor tkEntryTranspose tkEntryMouseSelect tkEntryAutoScan tkEntryButton1 tkEntryBackspace tkEntryClipboardKeysyms
  496.  
  497. # entry.tcl --
  498. #
  499. # This file defines the default bindings for Tk entry widgets and provides
  500. # procedures that help in implementing those bindings.
  501. #
  502. # @(#) entry.tcl 1.36 95/06/17 17:47:29
  503. #
  504. # Copyright (c) 1992-1994 The Regents of the University of California.
  505. # Copyright (c) 1994-1995 Sun Microsystems, Inc.
  506. #
  507. # See the file "license.terms" for information on usage and redistribution
  508. # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  509. #
  510.  
  511. #-------------------------------------------------------------------------
  512. # Elements of tkPriv that are used in this file:
  513. #
  514. # afterId -        If non-null, it means that auto-scanning is underway
  515. #            and it gives the "after" id for the next auto-scan
  516. #            command to be executed.
  517. # mouseMoved -        Non-zero means the mouse has moved a significant
  518. #            amount since the button went down (so, for example,
  519. #            start dragging out a selection).
  520. # pressX -        X-coordinate at which the mouse button was pressed.
  521. # selectMode -        The style of selection currently underway:
  522. #            char, word, or line.
  523. # x, y -        Last known mouse coordinates for scanning
  524. #            and auto-scanning.
  525. #-------------------------------------------------------------------------
  526.  
  527. # tkEntryClipboardKeysyms --
  528. # This procedure is invoked to identify the keys that correspond to
  529. # the "copy", "cut", and "paste" functions for the clipboard.
  530. #
  531. # Arguments:
  532. # copy -    Name of the key (keysym name plus modifiers, if any,
  533. #        such as "Meta-y") used for the copy operation.
  534. # cut -        Name of the key used for the cut operation.
  535. # paste -    Name of the key used for the paste operation.
  536.  
  537. proc tkEntryClipboardKeysyms {copy cut paste} {
  538.     bind Entry <$copy> {
  539.     if {[selection own -displayof %W] == "%W"} {
  540.         clipboard clear -displayof %W
  541.         catch {
  542.         clipboard append -displayof %W [selection get -displayof %W]
  543.         }
  544.     }
  545.     }
  546.     bind Entry <$cut> {
  547.     if {[selection own -displayof %W] == "%W"} {
  548.         clipboard clear -displayof %W
  549.         catch {
  550.         clipboard append -displayof %W [selection get -displayof %W]
  551.         %W delete sel.first sel.last
  552.         }
  553.     }
  554.     }
  555.     bind Entry <$paste> {
  556.     catch {
  557.         %W insert insert [selection get -displayof %W \
  558.             -selection CLIPBOARD]
  559.     }
  560.     }
  561. }
  562.  
  563. #-------------------------------------------------------------------------
  564. # The code below creates the default class bindings for entries.
  565. #-------------------------------------------------------------------------
  566.  
  567. # Standard Motif bindings:
  568.  
  569. bind Entry <1> {
  570.     tkEntryButton1 %W %x
  571.     %W selection clear
  572. }
  573. bind Entry <B1-Motion> {
  574.     set tkPriv(x) %x
  575.     tkEntryMouseSelect %W %x
  576. }
  577. bind Entry <Double-1> {
  578.     set tkPriv(selectMode) word
  579.     tkEntryMouseSelect %W %x
  580.     catch {%W icursor sel.first}
  581. }
  582. bind Entry <Triple-1> {
  583.     set tkPriv(selectMode) line
  584.     tkEntryMouseSelect %W %x
  585.     %W icursor 0
  586. }
  587. bind Entry <Shift-1> {
  588.     set tkPriv(selectMode) char
  589.     %W selection adjust @%x
  590. }
  591. bind Entry <Double-Shift-1>    {
  592.     set tkPriv(selectMode) word
  593.     tkEntryMouseSelect %W %x
  594. }
  595. bind Entry <Triple-Shift-1>    {
  596.     set tkPriv(selectMode) line
  597.     tkEntryMouseSelect %W %x
  598. }
  599. bind Entry <B1-Leave> {
  600.     set tkPriv(x) %x
  601.     tkEntryAutoScan %W
  602. }
  603. bind Entry <B1-Enter> {
  604.     tkCancelRepeat
  605. }
  606. bind Entry <ButtonRelease-1> {
  607.     tkCancelRepeat
  608. }
  609. bind Entry <Control-1> {
  610.     %W icursor @%x
  611. }
  612.  
  613. bind Entry <Left> {
  614.     tkEntrySetCursor %W [expr [%W index insert] - 1]
  615. }
  616. bind Entry <Right> {
  617.     tkEntrySetCursor %W [expr [%W index insert] + 1]
  618. }
  619. bind Entry <Shift-Left> {
  620.     tkEntryKeySelect %W [expr [%W index insert] - 1]
  621.     tkEntrySeeInsert %W
  622. }
  623. bind Entry <Shift-Right> {
  624.     tkEntryKeySelect %W [expr [%W index insert] + 1]
  625.     tkEntrySeeInsert %W
  626. }
  627. bind Entry <Control-Left> {
  628.     tkEntrySetCursor %W \
  629.         [string wordstart [%W get] [expr [%W index insert] - 1]]
  630. }
  631. bind Entry <Control-Right> {
  632.     tkEntrySetCursor %W [string wordend [%W get] [%W index insert]]
  633. }
  634. bind Entry <Shift-Control-Left> {
  635.     tkEntryKeySelect %W \
  636.         [string wordstart [%W get] [expr [%W index insert] - 1]]
  637.     tkEntrySeeInsert %W
  638. }
  639. bind Entry <Shift-Control-Right> {
  640.     tkEntryKeySelect %W [string wordend [%W get] [%W index insert]]
  641.     tkEntrySeeInsert %W
  642. }
  643. bind Entry <Home> {
  644.     tkEntrySetCursor %W 0
  645. }
  646. bind Entry <Shift-Home> {
  647.     tkEntryKeySelect %W 0
  648.     tkEntrySeeInsert %W
  649. }
  650. bind Entry <End> {
  651.     tkEntrySetCursor %W end
  652. }
  653. bind Entry <Shift-End> {
  654.     tkEntryKeySelect %W end
  655.     tkEntrySeeInsert %W
  656. }
  657.  
  658. bind Entry <Delete> {
  659.     if [%W selection present] {
  660.     %W delete sel.first sel.last
  661.     } else {
  662.     %W delete insert
  663.     }
  664. }
  665. bind Entry <BackSpace> {
  666.     tkEntryBackspace %W
  667. }
  668.  
  669. bind Entry <Control-space> {
  670.     %W selection from insert
  671. }
  672. bind Entry <Select> {
  673.     %W selection from insert
  674. }
  675. bind Entry <Control-Shift-space> {
  676.     %W selection adjust insert
  677. }
  678. bind Entry <Shift-Select> {
  679.     %W selection adjust insert
  680. }
  681. bind Entry <Control-slash> {
  682.     %W selection range 0 end
  683. }
  684. bind Entry <Control-backslash> {
  685.     %W selection clear
  686. }
  687. tkEntryClipboardKeysyms F16 F20 F18
  688.  
  689. bind Entry <KeyPress> {
  690.     tkEntryInsert %W %A
  691. }
  692.  
  693. # Ignore all Alt, Meta, and Control keypresses unless explicitly bound.
  694. # Otherwise, if a widget binding for one of these is defined, the
  695. # <KeyPress> class binding will also fire and insert the character,
  696. # which is wrong.  Ditto for Escape, Return, and Tab.
  697.  
  698. bind Entry <Alt-KeyPress> {# nothing}
  699. bind Entry <Meta-KeyPress> {# nothing}
  700. bind Entry <Control-KeyPress> {# nothing}
  701. bind Entry <Escape> {# nothing}
  702. bind Entry <Return> {# nothing}
  703. bind Entry <KP_Enter> {# nothing}
  704. bind Entry <Tab> {# nothing}
  705.  
  706. bind Entry <Insert> {
  707.     catch {tkEntryInsert %W [selection get -displayof %W]}
  708. }
  709.  
  710. # Additional emacs-like bindings:
  711.  
  712. if !$tk_strictMotif {
  713.     bind Entry <Control-a> {
  714.     tkEntrySetCursor %W 0
  715.     }
  716.     bind Entry <Control-b> {
  717.     tkEntrySetCursor %W [expr [%W index insert] - 1]
  718.     }
  719.     bind Entry <Control-d> {
  720.     %W delete insert
  721.     }
  722.     bind Entry <Control-e> {
  723.     tkEntrySetCursor %W end
  724.     }
  725.     bind Entry <Control-f> {
  726.     tkEntrySetCursor %W [expr [%W index insert] + 1]
  727.     }
  728.     bind Entry <Control-h> {
  729.     tkEntryBackspace %W
  730.     }
  731.     bind Entry <Control-k> {
  732.     %W delete insert end
  733.     }
  734.     bind Entry <Control-t> {
  735.     tkEntryTranspose %W
  736.     }
  737.     bind Entry <Meta-b> {
  738.     tkEntrySetCursor %W \
  739.         [string wordstart [%W get] [expr [%W index insert] - 1]]
  740.     }
  741.     bind Entry <Meta-d> {
  742.     %W delete insert [string wordend [%W get] [%W index insert]]
  743.     }
  744.     bind Entry <Meta-f> {
  745.     tkEntrySetCursor %W [string wordend [%W get] [%W index insert]]
  746.     }
  747.     bind Entry <Meta-BackSpace> {
  748.     %W delete [string wordstart [%W get] [expr [%W index insert] - 1]] \
  749.         insert
  750.     }
  751.     tkEntryClipboardKeysyms Meta-w Control-w Control-y
  752.  
  753.     # A few additional bindings of my own.
  754.  
  755.     bind Entry <2> {
  756.     %W scan mark %x
  757.     set tkPriv(x) %x
  758.     set tkPriv(y) %y
  759.     set tkPriv(mouseMoved) 0
  760.     }
  761.     bind Entry <B2-Motion> {
  762.     if {abs(%x-$tkPriv(x)) > 2} {
  763.         set tkPriv(mouseMoved) 1
  764.     }
  765.     %W scan dragto %x
  766.     }
  767.     bind Entry <ButtonRelease-2> {
  768.     if !$tkPriv(mouseMoved) {
  769.         catch {
  770.         %W insert @%x [selection get -displayof %W]
  771.         }
  772.     }
  773.     }
  774. }
  775.  
  776. # tkEntryButton1 --
  777. # This procedure is invoked to handle button-1 presses in entry
  778. # widgets.  It moves the insertion cursor, sets the selection anchor,
  779. # and claims the input focus.
  780. #
  781. # Arguments:
  782. # w -        The entry window in which the button was pressed.
  783. # x -        The x-coordinate of the button press.
  784.  
  785. proc tkEntryButton1 {w x} {
  786.     global tkPriv
  787.  
  788.     set tkPriv(selectMode) char
  789.     set tkPriv(mouseMoved) 0
  790.     set tkPriv(pressX) $x
  791.     $w icursor @$x
  792.     $w selection from @$x
  793.     if {[lindex [$w configure -state] 4] == "normal"} {focus $w}
  794. }
  795.  
  796. # tkEntryMouseSelect --
  797. # This procedure is invoked when dragging out a selection with
  798. # the mouse.  Depending on the selection mode (character, word,
  799. # line) it selects in different-sized units.  This procedure
  800. # ignores mouse motions initially until the mouse has moved from
  801. # one character to another or until there have been multiple clicks.
  802. #
  803. # Arguments:
  804. # w -        The entry window in which the button was pressed.
  805. # x -        The x-coordinate of the mouse.
  806.  
  807. proc tkEntryMouseSelect {w x} {
  808.     global tkPriv
  809.  
  810.     set cur [$w index @$x]
  811.     set anchor [$w index anchor]
  812.     if {($cur != $anchor) || (abs($tkPriv(pressX) - $x) >= 3)} {
  813.     set tkPriv(mouseMoved) 1
  814.     }
  815.     switch $tkPriv(selectMode) {
  816.     char {
  817.         if $tkPriv(mouseMoved) {
  818.         if {$cur < [$w index anchor]} {
  819.             $w selection to $cur
  820.         } else {
  821.             $w selection to [expr $cur+1]
  822.         }
  823.         }
  824.     }
  825.     word {
  826.         if {$cur < [$w index anchor]} {
  827.         $w selection range [string wordstart [$w get] $cur] \
  828.             [string wordend [$w get] [expr $anchor-1]]
  829.         } else {
  830.         $w selection range [string wordstart [$w get] $anchor] \
  831.             [string wordend [$w get] $cur]
  832.         }
  833.     }
  834.     line {
  835.         $w selection range 0 end
  836.     }
  837.     }
  838.     update idletasks
  839. }
  840.  
  841. # tkEntryAutoScan --
  842. # This procedure is invoked when the mouse leaves an entry window
  843. # with button 1 down.  It scrolls the window left or right,
  844. # depending on where the mouse is, and reschedules itself as an
  845. # "after" command so that the window continues to scroll until the
  846. # mouse moves back into the window or the mouse button is released.
  847. #
  848. # Arguments:
  849. # w -        The entry window.
  850.  
  851. proc tkEntryAutoScan {w} {
  852.     global tkPriv
  853.     set x $tkPriv(x)
  854.     if {$x >= [winfo width $w]} {
  855.     $w xview scroll 2 units
  856.     tkEntryMouseSelect $w $x
  857.     } elseif {$x < 0} {
  858.     $w xview scroll -2 units
  859.     tkEntryMouseSelect $w $x
  860.     }
  861.     set tkPriv(afterId) [after 50 tkEntryAutoScan $w]
  862. }
  863.  
  864. # tkEntryKeySelect --
  865. # This procedure is invoked when stroking out selections using the
  866. # keyboard.  It moves the cursor to a new position, then extends
  867. # the selection to that position.
  868. #
  869. # Arguments:
  870. # w -        The entry window.
  871. # new -        A new position for the insertion cursor (the cursor hasn't
  872. #        actually been moved to this position yet).
  873.  
  874. proc tkEntryKeySelect {w new} {
  875.     if ![$w selection present] {
  876.     $w selection from insert
  877.     $w selection to $new
  878.     } else {
  879.     $w selection adjust $new
  880.     }
  881.     $w icursor $new
  882. }
  883.  
  884. # tkEntryInsert --
  885. # Insert a string into an entry at the point of the insertion cursor.
  886. # If there is a selection in the entry, and it covers the point of the
  887. # insertion cursor, then delete the selection before inserting.
  888. #
  889. # Arguments:
  890. # w -        The entry window in which to insert the string
  891. # s -        The string to insert (usually just a single character)
  892.  
  893. proc tkEntryInsert {w s} {
  894.     if {$s == ""} {
  895.     return
  896.     }
  897.     catch {
  898.     set insert [$w index insert]
  899.     if {([$w index sel.first] <= $insert)
  900.         && ([$w index sel.last] >= $insert)} {
  901.         $w delete sel.first sel.last
  902.     }
  903.     }
  904.     $w insert insert $s
  905.     tkEntrySeeInsert $w
  906. }
  907.  
  908. # tkEntryBackspace --
  909. # Backspace over the character just before the insertion cursor.
  910. # If backspacing would move the cursor off the left edge of the
  911. # window, reposition the cursor at about the middle of the window.
  912. #
  913. # Arguments:
  914. # w -        The entry window in which to backspace.
  915.  
  916. proc tkEntryBackspace w {
  917.     if [$w selection present] {
  918.     $w delete sel.first sel.last
  919.     } else {
  920.     set x [expr {[$w index insert] - 1}]
  921.     if {$x >= 0} {$w delete $x}
  922.     if {[$w index @0] >= [$w index insert]} {
  923.         set range [$w xview]
  924.         set left [lindex $range 0]
  925.         set right [lindex $range 1]
  926.         $w xview moveto [expr $left - ($right - $left)/2.0]
  927.     }
  928.     }
  929. }
  930.  
  931. # tkEntrySeeInsert --
  932. # Make sure that the insertion cursor is visible in the entry window.
  933. # If not, adjust the view so that it is.
  934. #
  935. # Arguments:
  936. # w -        The entry window.
  937.  
  938. proc tkEntrySeeInsert w {
  939.     set c [$w index insert]
  940.     set left [$w index @0]
  941.     if {$left > $c} {
  942.     $w xview $c
  943.     return
  944.     }
  945.     set x [winfo width $w]
  946.     while {([$w index @$x] <= $c) && ($left < $c)} {
  947.     incr left
  948.     $w xview $left
  949.     }
  950. }
  951.  
  952. # tkEntrySetCursor -
  953. # Move the insertion cursor to a given position in an entry.  Also
  954. # clears the selection, if there is one in the entry, and makes sure
  955. # that the insertion cursor is visible.
  956. #
  957. # Arguments:
  958. # w -        The entry window.
  959. # pos -        The desired new position for the cursor in the window.
  960.  
  961. proc tkEntrySetCursor {w pos} {
  962.     $w icursor $pos
  963.     $w selection clear
  964.     tkEntrySeeInsert $w
  965. }
  966.  
  967. # tkEntryTranspose -
  968. # This procedure implements the "transpose" function for entry widgets.
  969. # It tranposes the characters on either side of the insertion cursor,
  970. # unless the cursor is at the end of the line.  In this case it
  971. # transposes the two characters to the left of the cursor.  In either
  972. # case, the cursor ends up to the right of the transposed characters.
  973. #
  974. # Arguments:
  975. # w -        The entry window.
  976.  
  977. proc tkEntryTranspose w {
  978.     set i [$w index insert]
  979.     if {$i < [$w index end]} {
  980.     incr i
  981.     }
  982.     set first [expr $i-2]
  983.     if {$first < 0} {
  984.     return
  985.     }
  986.     set new [string index [$w get] [expr $i-1]][string index [$w get] $first]
  987.     $w delete $first $i
  988.     $w insert insert $new
  989.     tkEntrySeeInsert $w
  990. }
  991. #@package: library/console tkConsoleBind tkConsoleOutput tkConsoleHistory tkConsoleInvoke tkConsoleInit tkConsoleExit tkConsolePrompt tkTextInsert
  992.  
  993. # console.tcl --
  994. #
  995. # This code constructs the console window for an application.  It
  996. # can be used by non-unix systems that do not have built-in support
  997. # for shells.
  998. #
  999. # @(#) console.tcl 1.16 95/10/03 22:14:30
  1000. #
  1001. # Copyright (c) 1995 Sun Microsystems, Inc.
  1002. #
  1003. # See the file "license.terms" for information on usage and redistribution
  1004. # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  1005. #
  1006.  
  1007. # TODO: fix history - last event skiped - change history command
  1008. #    or use "history event [expr [history nextid] - 1]]"
  1009. # TODO: history - remember partially written command
  1010. # TODO: get better default size for console -
  1011. #       auto configure based on font size???
  1012.  
  1013. # tkConsoleInit --
  1014. # This procedure constructs and configures the console windows.
  1015. #
  1016. # Arguments:
  1017. #     None.
  1018.  
  1019. proc tkConsoleInit {} {
  1020.     global tcl_platform
  1021.  
  1022.     text .console  -yscrollcommand ".sb set" -setgrid true
  1023.     scrollbar .sb -command ".console yview"
  1024.     pack .sb -side right -fill both
  1025.     pack .console -fill both -expand 1 -side left
  1026.     if {$tcl_platform(platform) == "macintosh"} {
  1027.         after idle {.console configure -font {Monaco 9 normal}}
  1028.     }
  1029.  
  1030.     tkConsoleBind .console
  1031.  
  1032.     .console tag configure stderr -foreground red
  1033.     .console tag configure stdout -foreground black
  1034.     .console tag configure stdin -foreground blue
  1035.  
  1036.     focus .console
  1037.     
  1038.     wm protocol . WM_DELETE_WINDOW { wm withdraw . }
  1039.     tkConsolePrompt
  1040. }
  1041.  
  1042. # tkConsoleInvoke --
  1043. # Processes the command line input.  If the command is complete it
  1044. # is evaled in the main interpreter.  Otherwise, the continuation
  1045. # prompt is added and more input may be added.
  1046. #
  1047. # Arguments:
  1048. # None.
  1049.  
  1050. proc tkConsoleInvoke {args} {
  1051.     set ranges [.console tag ranges input]
  1052.     set cmd ""
  1053.     if {$ranges != ""} {
  1054.     set pos 0
  1055.     while {[lindex $ranges $pos] != ""} {
  1056.         set start [lindex $ranges $pos]
  1057.         set end [lindex $ranges [incr pos]]
  1058.         append cmd [.console get $start $end]
  1059.         incr pos
  1060.     }
  1061.     }
  1062.     if {$cmd == ""} {
  1063.     tkConsolePrompt
  1064.     } elseif [info complete $cmd] {
  1065.     .console mark set output end
  1066.     .console tag delete input
  1067.     set result [interp record $cmd]
  1068.     if {$result != ""} {
  1069.         .console insert insert "$result\n"
  1070.     }
  1071.     tkConsoleHistory reset
  1072.     tkConsolePrompt
  1073.     } else {
  1074.     tkConsolePrompt partial
  1075.     }
  1076.     .console yview -pickplace insert
  1077. }
  1078.  
  1079. # tkConsoleHistory --
  1080. # This procedure implements command line history for the
  1081. # console.  In general is evals the history command in the
  1082. # main interpreter to obtain the history.  The global variable
  1083. # histNum is used to store the current location in the history.
  1084. #
  1085. # Arguments:
  1086. # cmd -    Which action to take: prev, next, reset.
  1087.  
  1088. set histNum 1
  1089. proc tkConsoleHistory {cmd} {
  1090.     global histNum
  1091.     
  1092.     switch $cmd {
  1093.         prev {
  1094.         incr histNum -1
  1095.         if {$histNum == 0} {
  1096.         set cmd {history event [expr [history nextid] -1]}
  1097.         } else {
  1098.         set cmd "history event $histNum"
  1099.         }
  1100.             if {[catch {interp eval $cmd} cmd]} {
  1101.                 incr histNum
  1102.                 return
  1103.             }
  1104.         .console delete promptEnd end
  1105.             .console insert promptEnd $cmd {input stdin}
  1106.         }
  1107.         next {
  1108.         incr histNum
  1109.         if {$histNum == 0} {
  1110.         set cmd {history event [expr [history nextid] -1]}
  1111.         } elseif {$histNum > 0} {
  1112.         set cmd ""
  1113.         set histNum 1
  1114.         } else {
  1115.         set cmd "history event $histNum"
  1116.         }
  1117.         if {$cmd != ""} {
  1118.         catch {interp eval $cmd} cmd
  1119.         }
  1120.         .console delete promptEnd end
  1121.         .console insert promptEnd $cmd {input stdin}
  1122.         }
  1123.         reset {
  1124.             set histNum 1
  1125.         }
  1126.     }
  1127. }
  1128.  
  1129. # tkConsolePrompt --
  1130. # This procedure draws the prompt.  If tcl_prompt1 or tcl_prompt2
  1131. # exists in the main interpreter it will be called to generate the 
  1132. # prompt.  Otherwise, a hard coded default prompt is printed.
  1133. #
  1134. # Arguments:
  1135. # partial -    Flag to specify which prompt to print.
  1136.  
  1137. proc tkConsolePrompt {{partial normal}} {
  1138.     if {$partial == "normal"} {
  1139.     set temp [.console index "end - 1 char"]
  1140.     .console mark set output end
  1141.         if [interp eval "info exists tcl_prompt1"] {
  1142.             interp eval "eval \[set tcl_prompt1\]"
  1143.         } else {
  1144.             puts -nonewline "tcl> "
  1145.         }
  1146.     } else {
  1147.     set temp [.console index output]
  1148.     .console mark set output end
  1149.         if [interp eval "info exists tcl_prompt2"] {
  1150.             interp eval "eval \[set tcl_prompt2\]"
  1151.         } else {
  1152.         puts -nonewline "> "
  1153.         }
  1154.     }
  1155.     .console mark set output $temp
  1156.     tkTextSetCursor .console end
  1157.     .console mark set promptEnd insert
  1158.     .console mark gravity promptEnd left
  1159. }
  1160.  
  1161. # tkConsoleBind --
  1162. # This procedure first ensures that the default bindings for the Text
  1163. # class have been defined.  Then certain bindings are overridden for
  1164. # the class.
  1165. #
  1166. # Arguments:
  1167. # None.
  1168.  
  1169. proc tkConsoleBind {win} {
  1170.     catch {tkTextBind dummy_arg}
  1171.     
  1172.     bindtags $win "$win Text . all"
  1173.  
  1174.     bind $win <Return> {
  1175.     %W mark set insert {end - 1c}
  1176.     tkTextInsert %W "\n"
  1177.     tkConsoleInvoke
  1178.     break
  1179.     }
  1180.     bind $win <Delete> {
  1181.     if {[%W tag nextrange sel 1.0 end] != ""} {
  1182.         %W tag remove sel sel.first promptEnd
  1183.     } else {
  1184.         if [%W compare insert < promptEnd] {
  1185.         break
  1186.         }
  1187.     }
  1188.     }
  1189.     bind $win <BackSpace> {
  1190.     if {[%W tag nextrange sel 1.0 end] != ""} {
  1191.         %W tag remove sel sel.first promptEnd
  1192.     } else {
  1193.         if [%W compare insert <= promptEnd] {
  1194.         break
  1195.         }
  1196.     }
  1197.     }
  1198.     bind $win <Control-a> {
  1199.     if [%W compare insert < promptEnd] {
  1200.         tkTextSetCursor %W {insert linestart}
  1201.     } else {
  1202.         tkTextSetCursor %W promptEnd
  1203.         }
  1204.     break
  1205.     }
  1206.     bind $win <Control-d> {
  1207.     if [%W compare insert < promptEnd] {
  1208.         break
  1209.     }
  1210.     }
  1211.     bind $win <Control-k> {
  1212.     if [%W compare insert < promptEnd] {
  1213.         %W mark set insert promptEnd
  1214.     }
  1215.     }
  1216.     bind $win <Control-t> {
  1217.     if [%W compare insert < promptEnd] {
  1218.         break
  1219.     }
  1220.     }
  1221.     bind $win <Meta-d> {
  1222.     if [%W compare insert < promptEnd] {
  1223.         break
  1224.     }
  1225.     }
  1226.     bind $win <Meta-BackSpace> {
  1227.     if [%W compare insert <= promptEnd] {
  1228.         break
  1229.     }
  1230.     }
  1231.     bind $win <Control-h> {
  1232.     if [%W compare insert <= promptEnd] {
  1233.         break
  1234.     }
  1235.     }
  1236.     bind $win <Control-p> {
  1237.     tkConsoleHistory prev
  1238.     break
  1239.     }
  1240.     bind $win <Control-n> {
  1241.     tkConsoleHistory next
  1242.     break
  1243.     }
  1244.     bind $win <Control-v> {
  1245.     if [%W compare insert > promptEnd] {
  1246.         catch {
  1247.         %W insert insert [selection get -displayof %W] {input stdin}
  1248.         %W see insert
  1249.         }
  1250.     }
  1251.     break
  1252.     }
  1253.     bind $win <F9> {
  1254.     eval destroy [winfo child .]
  1255.     source $tk_library/console.tcl
  1256.     }
  1257.     foreach copy {F16 Meta-w Control-i} {
  1258.     bind Text <$copy> {
  1259.         if {[selection own -displayof %W] == "%W"} {
  1260.         clipboard clear -displayof %W
  1261.         catch {
  1262.             clipboard append -displayof %W [selection get -displayof %W]
  1263.         }
  1264.         }
  1265.         break
  1266.     }
  1267.     }
  1268.     foreach paste {F18 Control-y} {
  1269.     bind $win <$paste> {
  1270.         catch {
  1271.             set clip [selection get -displayof %W -selection CLIPBOARD]
  1272.         set list [split $clip \n\r]
  1273.         tkTextInsert %W [lindex $list 0]
  1274.         foreach x [lrange $list 1 end] {
  1275.             %W mark set insert {end - 1c}
  1276.             tkTextInsert %W "\n"
  1277.             tkConsoleInvoke
  1278.             tkTextInsert %W $x
  1279.         }
  1280.         }
  1281.         break
  1282.     }
  1283.     }
  1284. }
  1285.  
  1286. # Replace the default implementation of tkTextInsert so that we can
  1287. # attach tags to user input
  1288.  
  1289. proc tkTextInsert {w s} {
  1290.     if {$s == ""} {
  1291.     return
  1292.     }
  1293.     catch {
  1294.     if {[$w compare sel.first <= insert]
  1295.         && [$w compare sel.last >= insert]} {
  1296.         $w tag remove sel sel.first promptEnd
  1297.         $w delete sel.first sel.last
  1298.     }
  1299.     }
  1300.     if {[$w compare insert < promptEnd]} {
  1301.     $w mark set insert end    
  1302.     }
  1303.     $w insert insert $s {input stdin}
  1304.     $w see insert
  1305. }
  1306.  
  1307. # tkConsoleOutput --
  1308. #
  1309. # This routine is called directly by ConsolePutsCmd to cause a string
  1310. # to be displayed in the console.
  1311. #
  1312. # Arguments:
  1313. # dest -    The output tag to be used: either "stderr" or "stdout".
  1314. # string -    The string to be displayed.
  1315.  
  1316. proc tkConsoleOutput {dest string} {
  1317.     .console insert output $string $dest
  1318.     .console see insert
  1319. }
  1320.  
  1321. # tkConsoleExit --
  1322. #
  1323. # This routine is called by ConsoleEventProc when the main window of
  1324. # the application is destroyed.
  1325. #
  1326. # Arguments:
  1327. # None.
  1328.  
  1329. proc tkConsoleExit {} {
  1330.     exit
  1331. }
  1332.  
  1333. # now initialize the console
  1334.  
  1335. tkConsoleInit
  1336. #@package: library/menu tkTraverseToMenu tkMenuUnpost tk_popup tkMbEnter tkMenuButtonDown tkTraverseWithinMenu tkPostOverPoint tkMenuFirstEntry tkMenuInvoke tkMbLeave tkFirstMenu tkMenuFindName tkMbMotion tkMenuLeave tkMenuMotion tkMbPost tkMenuLeftRight tkMenuNextEntry tkSaveGrabInfo tkMbButtonUp tkMenuEscape tkMenuFind
  1337.  
  1338. # menu.tcl --
  1339. #
  1340. # This file defines the default bindings for Tk menus and menubuttons.
  1341. # It also implements keyboard traversal of menus and implements a few
  1342. # other utility procedures related to menus.
  1343. #
  1344. # @(#) menu.tcl 1.55 95/09/25 14:15:29
  1345. #
  1346. # Copyright (c) 1992-1994 The Regents of the University of California.
  1347. # Copyright (c) 1994-1995 Sun Microsystems, Inc.
  1348. #
  1349. # See the file "license.terms" for information on usage and redistribution
  1350. # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  1351. #
  1352.  
  1353. #-------------------------------------------------------------------------
  1354. # Elements of tkPriv that are used in this file:
  1355. #
  1356. # cursor -        Saves the -cursor option for the posted menubutton.
  1357. # focus -        Saves the focus during a menu selection operation.
  1358. #            Focus gets restored here when the menu is unposted.
  1359. # grabGlobal -        Used in conjunction with tkPriv(oldGrab):  if
  1360. #            tkPriv(oldGrab) is non-empty, then tkPriv(grabGlobal)
  1361. #            contains either an empty string or "-global" to
  1362. #            indicate whether the old grab was a local one or
  1363. #            a global one.
  1364. # inMenubutton -    The name of the menubutton widget containing
  1365. #            the mouse, or an empty string if the mouse is
  1366. #            not over any menubutton.
  1367. # oldGrab -        Window that had the grab before a menu was posted.
  1368. #            Used to restore the grab state after the menu
  1369. #            is unposted.  Empty string means there was no
  1370. #            grab previously set.
  1371. # popup -        If a menu has been popped up via tk_popup, this
  1372. #            gives the name of the menu.  Otherwise this
  1373. #            value is empty.
  1374. # postedMb -        Name of the menubutton whose menu is currently
  1375. #            posted, or an empty string if nothing is posted
  1376. #            A grab is set on this widget.
  1377. # relief -        Used to save the original relief of the current
  1378. #            menubutton.
  1379. # window -        When the mouse is over a menu, this holds the
  1380. #            name of the menu;  it's cleared when the mouse
  1381. #            leaves the menu.
  1382. #-------------------------------------------------------------------------
  1383.  
  1384. #-------------------------------------------------------------------------
  1385. # Overall note:
  1386. # This file is tricky because there are four different ways that menus
  1387. # can be used:
  1388. #
  1389. # 1. As a pulldown from a menubutton.  This is the most common usage.
  1390. #    In this style, the variable tkPriv(postedMb) identifies the posted
  1391. #    menubutton.
  1392. # 2. As a torn-off menu copied from some other menu.  In this style
  1393. #    tkPriv(postedMb) is empty, and the top-level menu is no
  1394. #    override-redirect.
  1395. # 3. As an option menu, triggered from an option menubutton.  In thi
  1396. #    style tkPriv(postedMb) identifies the posted menubutton.
  1397. # 4. As a popup menu.  In this style tkPriv(postedMb) is empty and
  1398. #    the top-level menu is override-redirect.
  1399. #
  1400. # The various binding procedures use the  state described above to
  1401. # distinguish the various cases and take different actions in each
  1402. # case.
  1403. #-------------------------------------------------------------------------
  1404.  
  1405. #-------------------------------------------------------------------------
  1406. # The code below creates the default class bindings for menus
  1407. # and menubuttons.
  1408. #-------------------------------------------------------------------------
  1409.  
  1410. bind Menubutton <FocusIn> {}
  1411. bind Menubutton <Enter> {
  1412.     tkMbEnter %W
  1413. }
  1414. bind Menubutton <Leave> {
  1415.     tkMbLeave %W
  1416. }
  1417. bind Menubutton <1> {
  1418.     if {$tkPriv(inMenubutton) != ""} {
  1419.     tkMbPost $tkPriv(inMenubutton) %X %Y
  1420.     }
  1421. }
  1422. bind Menubutton <Motion> {
  1423.     tkMbMotion %W up %X %Y
  1424. }
  1425. bind Menubutton <B1-Motion> {
  1426.     tkMbMotion %W down %X %Y
  1427. }
  1428. bind Menubutton <ButtonRelease-1> {
  1429.     tkMbButtonUp %W
  1430. }
  1431. bind Menubutton <space> {
  1432.     tkMbPost %W
  1433.     tkMenuFirstEntry [%W cget -menu]
  1434. }
  1435. bind Menubutton <Return> {
  1436.     tkMbPost %W
  1437.     tkMenuFirstEntry [%W cget -menu]
  1438. }
  1439.  
  1440. # Must set focus when mouse enters a menu, in order to allow
  1441. # mixed-mode processing using both the mouse and the keyboard.
  1442.  
  1443. bind Menu <FocusIn> {}
  1444. bind Menu <Enter> {
  1445.     set tkPriv(window) %W
  1446.     focus %W
  1447. }
  1448. bind Menu <Leave> {
  1449.     tkMenuLeave %W %X %Y %s
  1450. }
  1451. bind Menu <Motion> {
  1452.     tkMenuMotion %W %y %s
  1453. }
  1454. bind Menu <ButtonPress> {
  1455.     tkMenuButtonDown %W
  1456. }
  1457. bind Menu <ButtonRelease> {
  1458.     tkMenuInvoke %W
  1459. }
  1460. bind Menu <space> {
  1461.     tkMenuKbdInvoke %W
  1462. }
  1463. bind Menu <Return> {
  1464.     tkMenuKbdInvoke %W
  1465. }
  1466. bind Menu <Escape> {
  1467.     tkMenuEscape %W
  1468. }
  1469. bind Menu <Left> {
  1470.     tkMenuLeftRight %W left
  1471. }
  1472. bind Menu <Right> {
  1473.     tkMenuLeftRight %W right
  1474. }
  1475. bind Menu <Up> {
  1476.     tkMenuNextEntry %W -1
  1477. }
  1478. bind Menu <Down> {
  1479.     tkMenuNextEntry %W +1
  1480. }
  1481. bind Menu <KeyPress> {
  1482.     tkTraverseWithinMenu %W %A
  1483. }
  1484.  
  1485. # The following bindings apply to all windows, and are used to
  1486. # implement keyboard menu traversal.
  1487.  
  1488. bind all <Alt-KeyPress> {
  1489.     tkTraverseToMenu %W %A
  1490. }
  1491. bind all <F10> {
  1492.     tkFirstMenu %W
  1493. }
  1494.  
  1495. # tkMbEnter --
  1496. # This procedure is invoked when the mouse enters a menubutton
  1497. # widget.  It activates the widget unless it is disabled.  Note:
  1498. # this procedure is only invoked when mouse button 1 is *not* down.
  1499. # The procedure tkMbB1Enter is invoked if the button is down.
  1500. #
  1501. # Arguments:
  1502. # w -            The  name of the widget.
  1503.  
  1504. proc tkMbEnter w {
  1505.     global tkPriv
  1506.  
  1507.     if {$tkPriv(inMenubutton) != ""} {
  1508.     tkMbLeave $tkPriv(inMenubutton)
  1509.     }
  1510.     set tkPriv(inMenubutton) $w
  1511.     if {[$w cget -state] != "disabled"} {
  1512.     $w configure -state active
  1513.     }
  1514. }
  1515.  
  1516. # tkMbLeave --
  1517. # This procedure is invoked when the mouse leaves a menubutton widget.
  1518. # It de-activates the widget, if the widget still exists.
  1519. #
  1520. # Arguments:
  1521. # w -            The  name of the widget.
  1522.  
  1523. proc tkMbLeave w {
  1524.     global tkPriv
  1525.  
  1526.     set tkPriv(inMenubutton) {}
  1527.     if ![winfo exists $w] {
  1528.     return
  1529.     }
  1530.     if {[$w cget -state] == "active"} {
  1531.     $w configure -state normal
  1532.     }
  1533. }
  1534.  
  1535. # tkMbPost --
  1536. # Given a menubutton, this procedure does all the work of posting
  1537. # its associated menu and unposting any other menu that is currently
  1538. # posted.
  1539. #
  1540. # Arguments:
  1541. # w -            The name of the menubutton widget whose menu
  1542. #            is to be posted.
  1543. # x, y -        Root coordinates of cursor, used for positioning
  1544. #            option menus.  If not specified, then the center
  1545. #            of the menubutton is used for an option menu.
  1546.  
  1547. proc tkMbPost {w {x {}} {y {}}} {
  1548.     global tkPriv
  1549.     if {([$w cget -state] == "disabled") || ($w == $tkPriv(postedMb))} {
  1550.     return
  1551.     }
  1552.     set menu [$w cget -menu]
  1553.     if {$menu == ""} {
  1554.     return
  1555.     }
  1556.     if ![string match $w.* $menu] {
  1557.     error "can't post $menu:  it isn't a descendant of $w (this is a new requirement in Tk versions 3.0 and later)"
  1558.     }
  1559.     set cur $tkPriv(postedMb)
  1560.     if {$cur != ""} {
  1561.     tkMenuUnpost {}
  1562.     }
  1563.     set tkPriv(cursor) [$w cget -cursor]
  1564.     set tkPriv(relief) [$w cget -relief]
  1565.     $w configure -cursor arrow
  1566.     $w configure -relief raised
  1567.     set tkPriv(postedMb) $w
  1568.     set tkPriv(focus) [focus]
  1569.     $menu activate none
  1570.  
  1571.     # If this looks like an option menubutton then post the menu so
  1572.     # that the current entry is on top of the mouse.  Otherwise post
  1573.     # the menu just below the menubutton, as for a pull-down.
  1574.  
  1575.     if {([$w cget -indicatoron] == 1) && ([$w cget -textvariable] != "")} {
  1576.     if {$y == ""} {
  1577.         set x [expr [winfo rootx $w] + [winfo width $w]/2]
  1578.         set y [expr [winfo rooty $w] + [winfo height $w]/2]
  1579.     }
  1580.     tkPostOverPoint $menu $x $y [tkMenuFindName $menu [$w cget -text]]
  1581.     } else {
  1582.     $menu post [winfo rootx $w] [expr [winfo rooty $w]+[winfo height $w]]
  1583.     }
  1584.     focus $menu
  1585.     tkSaveGrabInfo $w
  1586.     grab -global $w
  1587. }
  1588.  
  1589. # tkMenuUnpost --
  1590. # This procedure unposts a given menu, plus all of its ancestors up
  1591. # to (and including) a menubutton, if any.  It also restores various
  1592. # values to what they were before the menu was posted, and releases
  1593. # a grab if there's a menubutton involved.  Special notes:
  1594. # 1. It's important to unpost all menus before releasing the grab, so
  1595. #    that any Enter-Leave events (e.g. from menu back to main
  1596. #    application) have mode NotifyGrab.
  1597. # 2. Be sure to enclose various groups of commands in "catch" so that
  1598. #    the procedure will complete even if the menubutton or the menu
  1599. #    or the grab window has been deleted.
  1600. #
  1601. # Arguments:
  1602. # menu -        Name of a menu to unpost.  Ignored if there
  1603. #            is a posted menubutton.
  1604.  
  1605. proc tkMenuUnpost menu {
  1606.     global tkPriv
  1607.     set mb $tkPriv(postedMb)
  1608.  
  1609.     # Restore focus right away (otherwise X will take focus away when
  1610.     # the menu is unmapped and under some window managers (e.g. olvwm)
  1611.     # we'll lose the focus completely).
  1612.  
  1613.     catch {focus $tkPriv(focus)}
  1614.     set tkPriv(focus) ""
  1615.  
  1616.     # Unpost menu(s) and restore some stuff that's dependent on
  1617.     # what was posted.
  1618.  
  1619.     catch {
  1620.     if {$mb != ""} {
  1621.         set menu [$mb cget -menu]
  1622.         $menu unpost
  1623.         set tkPriv(postedMb) {}
  1624.         $mb configure -cursor $tkPriv(cursor)
  1625.         $mb configure -relief $tkPriv(relief)
  1626.     } elseif {$tkPriv(popup) != ""} {
  1627.         $tkPriv(popup) unpost
  1628.         set tkPriv(popup) {}
  1629.     } elseif {[wm overrideredirect $menu]} {
  1630.         # We're in a cascaded sub-menu from a torn-off menu or popup.
  1631.         # Unpost all the menus up to the toplevel one (but not
  1632.         # including the top-level torn-off one) and deactivate the
  1633.         # top-level torn off menu if there is one.
  1634.  
  1635.         while 1 {
  1636.         set parent [winfo parent $menu]
  1637.         if {([winfo class $parent] != "Menu")
  1638.             || ![winfo ismapped $parent]} {
  1639.             break
  1640.         }
  1641.         $parent activate none
  1642.         $parent postcascade none
  1643.         if {![wm overrideredirect $parent]} {
  1644.             break
  1645.         }
  1646.         set menu $parent
  1647.         }
  1648.         $menu unpost
  1649.     }
  1650.     }
  1651.  
  1652.     # Release grab, if any, and restore the previous grab, if there
  1653.     # was one.
  1654.  
  1655.     if {$menu != ""} {
  1656.     set grab [grab current $menu]
  1657.     if {$grab != ""} {
  1658.         grab release $grab
  1659.     }
  1660.     }
  1661.     if {$tkPriv(oldGrab) != ""} {
  1662.     if {$tkPriv(grabStatus) == "global"} {
  1663.         grab set -global $tkPriv(oldGrab)
  1664.     } else {
  1665.         grab set $tkPriv(oldGrab)
  1666.     }
  1667.     set tkPriv(oldGrab) ""
  1668.     }
  1669. }
  1670.  
  1671. # tkMbMotion --
  1672. # This procedure handles mouse motion events inside menubuttons, and
  1673. # also outside menubuttons when a menubutton has a grab (e.g. when a
  1674. # menu selection operation is in progress).
  1675. #
  1676. # Arguments:
  1677. # w -            The name of the menubutton widget.
  1678. # upDown -         "down" means button 1 is pressed, "up" means
  1679. #            it isn't.
  1680. # rootx, rooty -    Coordinates of mouse, in (virtual?) root window.
  1681.  
  1682. proc tkMbMotion {w upDown rootx rooty} {
  1683.     global tkPriv
  1684.  
  1685.     if {$tkPriv(inMenubutton) == $w} {
  1686.     return
  1687.     }
  1688.     set new [winfo containing $rootx $rooty]
  1689.     if {($new != $tkPriv(inMenubutton)) && (($new == "")
  1690.         || ([winfo toplevel $new] == [winfo toplevel $w]))} {
  1691.     if {$tkPriv(inMenubutton) != ""} {
  1692.         tkMbLeave $tkPriv(inMenubutton)
  1693.     }
  1694.     if {($new != "") && ([winfo class $new] == "Menubutton")
  1695.         && ([$new cget -indicatoron] == 0)} {
  1696.         if {$upDown == "down"} {
  1697.         tkMbPost $new $rootx $rooty
  1698.         } else {
  1699.         tkMbEnter $new
  1700.         }
  1701.     }
  1702.     }
  1703. }
  1704.  
  1705. # tkMbButtonUp --
  1706. # This procedure is invoked to handle button 1 releases for menubuttons.
  1707. # If the release happens inside the menubutton then leave its menu
  1708. # posted with element 0 activated.  Otherwise, unpost the menu.
  1709. #
  1710. # Arguments:
  1711. # w -            The name of the menubutton widget.
  1712.  
  1713. proc tkMbButtonUp w {
  1714.     global tkPriv
  1715.  
  1716.     if  {($tkPriv(postedMb) == $w) && ($tkPriv(inMenubutton) == $w)} {
  1717.     tkMenuFirstEntry [$tkPriv(postedMb) cget -menu]
  1718.     } else {
  1719.     tkMenuUnpost {}
  1720.     }
  1721. }
  1722.  
  1723. # tkMenuMotion --
  1724. # This procedure is called to handle mouse motion events for menus.
  1725. # It does two things.  First, it resets the active element in the
  1726. # menu, if the mouse is over the menu.  Second, if a mouse button
  1727. # is down, it posts and unposts cascade entries to match the mouse
  1728. # position.
  1729. #
  1730. # Arguments:
  1731. # menu -        The menu window.
  1732. # y -            The y position of the mouse.
  1733. # state -        Modifier state (tells whether buttons are down).
  1734.  
  1735. proc tkMenuMotion {menu y state} {
  1736.     global tkPriv
  1737.     if {$menu == $tkPriv(window)} {
  1738.     $menu activate @$y
  1739.     }
  1740.     if {($state & 0x1f00) != 0} {
  1741.     $menu postcascade active
  1742.     }
  1743. }
  1744.  
  1745. # tkMenuButtonDown --
  1746. # Handles button presses in menus.  There are a couple of tricky things
  1747. # here:
  1748. # 1. Change the posted cascade entry (if any) to match the mouse position.
  1749. # 2. If there is a posted menubutton, must grab to the menubutton;  this
  1750. #    overrrides the implicit grab on button press, so that the menu
  1751. #    button can track mouse motions over other menubuttons and change
  1752. #    the posted menu.
  1753. # 3. If there's no posted menubutton (e.g. because we're a torn-off menu
  1754. #    or one of its descendants) must grab to the top-level menu so that
  1755. #    we can track mouse motions across the entire menu hierarchy.
  1756. #
  1757. # Arguments:
  1758. # menu -        The menu window.
  1759.  
  1760. proc tkMenuButtonDown menu {
  1761.     global tkPriv
  1762.     $menu postcascade active
  1763.     if {$tkPriv(postedMb) != ""} {
  1764.     grab -global $tkPriv(postedMb)
  1765.     } else {
  1766.     while {[wm overrideredirect $menu]
  1767.         && ([winfo class [winfo parent $menu]] == "Menu")
  1768.         && [winfo ismapped [winfo parent $menu]]} {
  1769.         set menu [winfo parent $menu]
  1770.     }
  1771.  
  1772.     # Don't update grab information if the grab window isn't changing.
  1773.     # Otherwise, we'll get an error when we unpost the menus and
  1774.     # restore the grab, since the old grab window will not be viewable
  1775.     # anymore.
  1776.  
  1777.     if {$menu != [grab current $menu]} {
  1778.         tkSaveGrabInfo $menu
  1779.     }
  1780.  
  1781.     # Must re-grab even if the grab window hasn't changed, in order
  1782.     # to release the implicit grab from the button press.
  1783.  
  1784.     grab -global $menu
  1785.     }
  1786. }
  1787.  
  1788. # tkMenuLeave --
  1789. # This procedure is invoked to handle Leave events for a menu.  It
  1790. # deactivates everything unless the active element is a cascade element
  1791. # and the mouse is now over the submenu.
  1792. #
  1793. # Arguments:
  1794. # menu -        The menu window.
  1795. # rootx, rooty -    Root coordinates of mouse.
  1796. # state -        Modifier state.
  1797.  
  1798. proc tkMenuLeave {menu rootx rooty state} {
  1799.     global tkPriv
  1800.     set tkPriv(window) {}
  1801.     if {[$menu index active] == "none"} {
  1802.     return
  1803.     }
  1804.     if {([$menu type active] == "cascade")
  1805.         && ([winfo containing $rootx $rooty]
  1806.         == [$menu entrycget active -menu])} {
  1807.     return
  1808.     }
  1809.     $menu activate none
  1810. }
  1811.  
  1812. # tkMenuInvoke --
  1813. # This procedure is invoked when button 1 is released over a menu.
  1814. # It invokes the appropriate menu action and unposts the menu if
  1815. # it came from a menubutton.
  1816. #
  1817. # Arguments:
  1818. # w -            Name of the menu widget.
  1819.  
  1820. proc tkMenuInvoke w {
  1821.     global tkPriv
  1822.  
  1823.     if {$tkPriv(window) == ""} {
  1824.     # Mouse was pressed over a menu without a menu button, then
  1825.     # dragged off the menu (possibly with a cascade posted) and
  1826.     # released.  Unpost everything and quit.
  1827.  
  1828.     $w postcascade none
  1829.     $w activate none
  1830.     tkMenuUnpost $w
  1831.     return
  1832.     }
  1833.     if {[$w type active] == "cascade"} {
  1834.     $w postcascade active
  1835.     set menu [$w entrycget active -menu]
  1836.     tkMenuFirstEntry $menu
  1837.     } elseif {[$w type active] == "tearoff"} {
  1838.     tkMenuUnpost $w
  1839.     tkTearOffMenu $w
  1840.     } else {
  1841.     tkMenuUnpost $w
  1842.     uplevel #0 [list $w invoke active]
  1843.     }
  1844. }
  1845.  
  1846. # tkMenuKbdInvoke --
  1847. # This procedure is invoked when enter or space is pressed over a menu.
  1848. # It invokes the appropriate menu action and unposts the menu if
  1849. # it came from a menubutton.
  1850. #
  1851. # Arguments:
  1852. # w -            Name of the menu widget.
  1853.  
  1854. proc tkMenuKbdInvoke w {
  1855.     global tkPriv
  1856.  
  1857.     if {[$w type active] == "cascade"} {
  1858.     $w postcascade active
  1859.     set menu [$w entrycget active -menu]
  1860.     tkMenuFirstEntry $menu
  1861.     } elseif {[$w type active] == "tearoff"} {
  1862.     tkMenuUnpost $w
  1863.     tkTearOffMenu $w
  1864.     } else {
  1865.     tkMenuUnpost $w
  1866.     uplevel #0 [list $w invoke active]
  1867.     }
  1868. }
  1869. # tkMenuEscape --
  1870. # This procedure is invoked for the Cancel (or Escape) key.  It unposts
  1871. # the given menu and, if it is the top-level menu for a menu button,
  1872. # unposts the menu button as well.
  1873. #
  1874. # Arguments:
  1875. # menu -        Name of the menu window.
  1876.  
  1877. proc tkMenuEscape menu {
  1878.     if {[winfo class [winfo parent $menu]] != "Menu"} {
  1879.     tkMenuUnpost $menu
  1880.     } else {
  1881.     tkMenuLeftRight $menu -1
  1882.     }
  1883. }
  1884.  
  1885. # tkMenuLeftRight --
  1886. # This procedure is invoked to handle "left" and "right" traversal
  1887. # motions in menus.  It traverses to the next menu in a menu bar,
  1888. # or into or out of a cascaded menu.
  1889. #
  1890. # Arguments:
  1891. # menu -        The menu that received the keyboard
  1892. #            event.
  1893. # direction -        Direction in which to move: "left" or "right"
  1894.  
  1895. proc tkMenuLeftRight {menu direction} {
  1896.     global tkPriv
  1897.  
  1898.     # First handle traversals into and out of cascaded menus.
  1899.  
  1900.     if {$direction == "right"} {
  1901.     set count 1
  1902.     if {[$menu type active] == "cascade"} {
  1903.         $menu postcascade active
  1904.         set m2 [$menu entrycget active -menu]
  1905.         if {$m2 != ""} {
  1906.         tkMenuFirstEntry $m2
  1907.         }
  1908.         return
  1909.     }
  1910.     } else {
  1911.     set count -1
  1912.     set m2 [winfo parent $menu]
  1913.     if {[winfo class $m2] == "Menu"} {
  1914.         $menu activate none
  1915.         focus $m2
  1916.  
  1917.         # This code unposts any posted submenu in the parent.
  1918.  
  1919.         set tmp [$m2 index active]
  1920.         $m2 activate none
  1921.         $m2 activate $tmp
  1922.         return
  1923.     }
  1924.     }
  1925.  
  1926.     # Can't traverse into or out of a cascaded menu.  Go to the next
  1927.     # or previous menubutton, if that makes sense.
  1928.  
  1929.     set w $tkPriv(postedMb)
  1930.     if {$w == ""} {
  1931.     return
  1932.     }
  1933.     set buttons [winfo children [winfo parent $w]]
  1934.     set length [llength $buttons]
  1935.     set i [expr [lsearch -exact $buttons $w] + $count]
  1936.     while 1 {
  1937.     while {$i < 0} {
  1938.         incr i $length
  1939.     }
  1940.     while {$i >= $length} {
  1941.         incr i -$length
  1942.     }
  1943.     set mb [lindex $buttons $i]
  1944.     if {([winfo class $mb] == "Menubutton")
  1945.         && ([$mb cget -state] != "disabled")
  1946.         && ([$mb cget -menu] != "")
  1947.         && ([[$mb cget -menu] index last] != "none")} {
  1948.         break
  1949.     }
  1950.     if {$mb == $w} {
  1951.         return
  1952.     }
  1953.     incr i $count
  1954.     }
  1955.     tkMbPost $mb
  1956.     tkMenuFirstEntry [$mb cget -menu]
  1957. }
  1958.  
  1959. # tkMenuNextEntry --
  1960. # Activate the next higher or lower entry in the posted menu,
  1961. # wrapping around at the ends.  Disabled entries are skipped.
  1962. #
  1963. # Arguments:
  1964. # menu -            Menu window that received the keystroke.
  1965. # count -            1 means go to the next lower entry,
  1966. #                -1 means go to the next higher entry.
  1967.  
  1968. proc tkMenuNextEntry {menu count} {
  1969.     global tkPriv
  1970.     if {[$menu index last] == "none"} {
  1971.     return
  1972.     }
  1973.     set length [expr [$menu index last]+1]
  1974.     set active [$menu index active]
  1975.     if {$active == "none"} {
  1976.     set i 0
  1977.     } else {
  1978.     set i [expr $active + $count]
  1979.     }
  1980.     while 1 {
  1981.     while {$i < 0} {
  1982.         incr i $length
  1983.     }
  1984.     while {$i >= $length} {
  1985.         incr i -$length
  1986.     }
  1987.     if {[catch {$menu entrycget $i -state} state] == 0} {
  1988.         if {$state != "disabled"} {
  1989.         break
  1990.         }
  1991.     }
  1992.     if {$i == $active} {
  1993.         return
  1994.     }
  1995.     incr i $count
  1996.     }
  1997.     $menu activate $i
  1998.     $menu postcascade $i
  1999. }
  2000.  
  2001. # tkMenuFind --
  2002. # This procedure searches the entire window hierarchy under w for
  2003. # a menubutton that isn't disabled and whose underlined character
  2004. # is "char".  It returns the name of that window, if found, or an
  2005. # empty string if no matching window was found.  If "char" is an
  2006. # empty string then the procedure returns the name of the first
  2007. # menubutton found that isn't disabled.
  2008. #
  2009. # Arguments:
  2010. # w -                Name of window where key was typed.
  2011. # char -            Underlined character to search for;
  2012. #                may be either upper or lower case, and
  2013. #                will match either upper or lower case.
  2014.  
  2015. proc tkMenuFind {w char} {
  2016.     global tkPriv
  2017.     set char [string tolower $char]
  2018.  
  2019.     foreach child [winfo child $w] {
  2020.     switch [winfo class $child] {
  2021.         Menubutton {
  2022.         set char2 [string index [$child cget -text] \
  2023.             [$child cget -underline]]
  2024.         if {([string compare $char [string tolower $char2]] == 0)
  2025.             || ($char == "")} {
  2026.             if {[$child cget -state] != "disabled"} {
  2027.             return $child
  2028.             }
  2029.         }
  2030.         }
  2031.         Frame {
  2032.         set match [tkMenuFind $child $char]
  2033.         if {$match != ""} {
  2034.             return $match
  2035.         }
  2036.         }
  2037.     }
  2038.     }
  2039.     return {}
  2040. }
  2041.  
  2042. # tkTraverseToMenu --
  2043. # This procedure implements keyboard traversal of menus.  Given an
  2044. # ASCII character "char", it looks for a menubutton with that character
  2045. # underlined.  If one is found, it posts the menubutton's menu
  2046. #
  2047. # Arguments:
  2048. # w -                Window in which the key was typed (selects
  2049. #                a toplevel window).
  2050. # char -            Character that selects a menu.  The case
  2051. #                is ignored.  If an empty string, nothing
  2052. #                happens.
  2053.  
  2054. proc tkTraverseToMenu {w char} {
  2055.     if {$char == ""} {
  2056.     return
  2057.     }
  2058.     while {[winfo class $w] == "Menu"} {
  2059.     set w [winfo parent $w]
  2060.     }
  2061.     set w [tkMenuFind [winfo toplevel $w] $char]
  2062.     if {$w != ""} {
  2063.     tkMbPost $w
  2064.     tkMenuFirstEntry [$w cget -menu]
  2065.     }
  2066. }
  2067.  
  2068. # tkFirstMenu --
  2069. # This procedure traverses to the first menubutton in the toplevel
  2070. # for a given window, and posts that menubutton's menu.
  2071. #
  2072. # Arguments:
  2073. # w -                Name of a window.  Selects which toplevel
  2074. #                to search for menubuttons.
  2075.  
  2076. proc tkFirstMenu w {
  2077.     set w [tkMenuFind [winfo toplevel $w] ""]
  2078.     if {$w != ""} {
  2079.     tkMbPost $w
  2080.     tkMenuFirstEntry [$w cget -menu]
  2081.     }
  2082. }
  2083.  
  2084. # tkTraverseWithinMenu
  2085. # This procedure implements keyboard traversal within a menu.  It
  2086. # searches for an entry in the menu that has "char" underlined.  If
  2087. # such an entry is found, it is invoked and the menu is unposted.
  2088. #
  2089. # Arguments:
  2090. # w -                The name of the menu widget.
  2091. # char -            The character to look for;  case is
  2092. #                ignored.  If the string is empty then
  2093. #                nothing happens.
  2094.  
  2095. proc tkTraverseWithinMenu {w char} {
  2096.     if {$char == ""} {
  2097.     return
  2098.     }
  2099.     set char [string tolower $char]
  2100.     set last [$w index last]
  2101.     if {$last == "none"} {
  2102.     return
  2103.     }
  2104.     for {set i 0} {$i <= $last} {incr i} {
  2105.     if [catch {set char2 [string index \
  2106.         [$w entrycget $i -label] \
  2107.         [$w entrycget $i -underline]]}] {
  2108.         continue
  2109.     }
  2110.     if {[string compare $char [string tolower $char2]] == 0} {
  2111.         if {[$w type $i] == "cascade"} {
  2112.         $w postcascade $i
  2113.         $w activate $i
  2114.         set m2 [$w entrycget $i -menu]
  2115.         if {$m2 != ""} {
  2116.             tkMenuFirstEntry $m2
  2117.         }
  2118.         } else {
  2119.         tkMenuUnpost $w
  2120.         uplevel #0 [list $w invoke $i]
  2121.         }
  2122.         return
  2123.     }
  2124.     }
  2125. }
  2126.  
  2127. # tkMenuFirstEntry --
  2128. # Given a menu, this procedure finds the first entry that isn't
  2129. # disabled or a tear-off or separator, and activates that entry.
  2130. # However, if there is already an active entry in the menu (e.g.,
  2131. # because of a previous call to tkPostOverPoint) then the active
  2132. # entry isn't changed.  This procedure also sets the input focus
  2133. # to the menu.
  2134. #
  2135. # Arguments:
  2136. # menu -        Name of the menu window (possibly empty).
  2137.  
  2138. proc tkMenuFirstEntry menu {
  2139.     if {$menu == ""} {
  2140.     return
  2141.     }
  2142.     focus $menu
  2143.     if {[$menu index active] != "none"} {
  2144.     return
  2145.     }
  2146.     set last [$menu index last]
  2147.     if {$last == "none"} {
  2148.     return
  2149.     }
  2150.     for {set i 0} {$i <= $last} {incr i} {
  2151.     if {([catch {set state [$menu entrycget $i -state]}] == 0)
  2152.         && ($state != "disabled") && ([$menu type $i] != "tearoff")} {
  2153.         $menu activate $i
  2154.         return
  2155.     }
  2156.     }
  2157. }
  2158.  
  2159. # tkMenuFindName --
  2160. # Given a menu and a text string, return the index of the menu entry
  2161. # that displays the string as its label.  If there is no such entry,
  2162. # return an empty string.  This procedure is tricky because some names
  2163. # like "active" have a special meaning in menu commands, so we can't
  2164. # always use the "index" widget command.
  2165. #
  2166. # Arguments:
  2167. # menu -        Name of the menu widget.
  2168. # s -            String to look for.
  2169.  
  2170. proc tkMenuFindName {menu s} {
  2171.     set i ""
  2172.     if {![regexp {^active$|^last$|^none$|^[0-9]|^@} $s]} {
  2173.     catch {set i [$menu index $s]}
  2174.     return $i
  2175.     }
  2176.     set last [$menu index last]
  2177.     if {$last == "none"} {
  2178.     return
  2179.     }
  2180.     for {set i 0} {$i <= $last} {incr i} {
  2181.     if ![catch {$menu entrycget $i -label} label] {
  2182.         if {$label == $s} {
  2183.         return $i
  2184.         }
  2185.     }
  2186.     }
  2187.     return ""
  2188. }
  2189.  
  2190. # tkPostOverPoint --
  2191. # This procedure posts a given menu such that a given entry in the
  2192. # menu is centered over a given point in the root window.  It also
  2193. # activates the given entry.
  2194. #
  2195. # Arguments:
  2196. # menu -        Menu to post.
  2197. # x, y -        Root coordinates of point.
  2198. # entry -        Index of entry within menu to center over (x,y).
  2199. #            If omitted or specified as {}, then the menu's
  2200. #            upper-left corner goes at (x,y).
  2201.  
  2202. proc tkPostOverPoint {menu x y {entry {}}}  {
  2203.     if {$entry != {}} {
  2204.     if {$entry == [$menu index last]} {
  2205.         incr y [expr -([$menu yposition $entry] \
  2206.             + [winfo reqheight $menu])/2]
  2207.     } else {
  2208.         incr y [expr -([$menu yposition $entry] \
  2209.             + [$menu yposition [expr $entry+1]])/2]
  2210.     }
  2211.     incr x [expr -[winfo reqwidth $menu]/2]
  2212.     }
  2213.     $menu post $x $y
  2214.     if {($entry != {}) && ([$menu entrycget $entry -state] != "disabled")} {
  2215.     $menu activate $entry
  2216.     }
  2217. }
  2218.  
  2219. # tkSaveGrabInfo --
  2220. # Sets the variables tkPriv(oldGrab) and tkPriv(grabStatus) to record
  2221. # the state of any existing grab on the w's display.
  2222. #
  2223. # Arguments:
  2224. # w -            Name of a window;  used to select the display
  2225. #            whose grab information is to be recorded.
  2226.  
  2227. proc tkSaveGrabInfo w {
  2228.     global tkPriv
  2229.     set tkPriv(oldGrab) [grab current $w]
  2230.     if {$tkPriv(oldGrab) != ""} {
  2231.     set tkPriv(grabStatus) [grab status $tkPriv(oldGrab)]
  2232.     }
  2233. }
  2234.  
  2235. # tk_popup --
  2236. # This procedure pops up a menu and sets things up for traversing
  2237. # the menu and its submenus.
  2238. #
  2239. # Arguments:
  2240. # menu -        Name of the menu to be popped up.
  2241. # x, y -        Root coordinates at which to pop up the
  2242. #            menu.
  2243. # entry -        Index of a menu entry to center over (x,y).
  2244. #            If omitted or specified as {}, then menu's
  2245. #            upper-left corner goes at (x,y).
  2246.  
  2247. proc tk_popup {menu x y {entry {}}} {
  2248.     global tkPriv
  2249.     if {($tkPriv(popup) != "") || ($tkPriv(postedMb) != "")} {
  2250.     tkMenuUnpost {}
  2251.     }
  2252.     tkPostOverPoint $menu $x $y $entry
  2253.     tkSaveGrabInfo $menu
  2254.     grab -global $menu
  2255.     set tkPriv(popup) $menu
  2256.     set tkPriv(focus) [focus]
  2257.     focus $menu
  2258. }
  2259. #@package: library/obsolete tk_bindForTraversal tk_menuBar
  2260.  
  2261. # obsolete.tcl --
  2262. #
  2263. # This file contains obsolete procedures that people really shouldn't
  2264. # be using anymore, but which are kept around for backward compatibility.
  2265. #
  2266. # @(#) obsolete.tcl 1.2 94/12/17 16:05:21
  2267. #
  2268. # Copyright (c) 1994 The Regents of the University of California.
  2269. # Copyright (c) 1994 Sun Microsystems, Inc.
  2270. #
  2271. # See the file "license.terms" for information on usage and redistribution
  2272. # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  2273. #
  2274.  
  2275. # The procedures below are here strictly for backward compatibility with
  2276. # Tk version 3.6 and earlier.  The procedures are no longer needed, so
  2277. # they are no-ops.  You should not use these procedures anymore, since
  2278. # they may be removed in some future release.
  2279.  
  2280. proc tk_menuBar args {}
  2281. proc tk_bindForTraversal args {}
  2282. #@package: library/listbox tkListboxBeginSelect tkListboxSelectAll tkListboxUpDown tkListboxBeginExtend tkListboxDataExtend tkListboxExtendUpDown tkListboxBeginToggle tkListboxMotion tkListboxAutoScan tkListboxCancel
  2283.  
  2284. # listbox.tcl --
  2285. #
  2286. # This file defines the default bindings for Tk listbox widgets
  2287. # and provides procedures that help in implementing those bindings.
  2288. #
  2289. # @(#) listbox.tcl 1.13 95/08/22 08:50:03
  2290. #
  2291. # Copyright (c) 1994 The Regents of the University of California.
  2292. # Copyright (c) 1994-1995 Sun Microsystems, Inc.
  2293. #
  2294. # See the file "license.terms" for information on usage and redistribution
  2295. # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  2296.  
  2297. #--------------------------------------------------------------------------
  2298. # tkPriv elements used in this file:
  2299. #
  2300. # afterId -        Token returned by "after" for autoscanning.
  2301. # listboxPrev -        The last element to be selected or deselected
  2302. #            during a selection operation.
  2303. # listboxSelection -    All of the items that were selected before the
  2304. #            current selection operation (such as a mouse
  2305. #            drag) started;  used to cancel an operation.
  2306. #--------------------------------------------------------------------------
  2307.  
  2308. #-------------------------------------------------------------------------
  2309. # The code below creates the default class bindings for listboxes.
  2310. #-------------------------------------------------------------------------
  2311.  
  2312. # Note: the check for existence of %W below is because this binding
  2313. # is sometimes invoked after a window has been deleted (e.g. because
  2314. # there is a double-click binding on the widget that deletes it).  Users
  2315. # can put "break"s in their bindings to avoid the error, but this check
  2316. # makes that unnecessary.
  2317.  
  2318. bind Listbox <1> {
  2319.     if [winfo exists %W] {
  2320.     tkListboxBeginSelect %W [%W index @%x,%y]
  2321.     }
  2322. }
  2323. bind Listbox <B1-Motion> {
  2324.     set tkPriv(x) %x
  2325.     set tkPriv(y) %y
  2326.     tkListboxMotion %W [%W index @%x,%y]
  2327. }
  2328. bind Listbox <ButtonRelease-1> {
  2329.     tkCancelRepeat
  2330.     %W activate @%x,%y
  2331. }
  2332. bind Listbox <Shift-1> {
  2333.     tkListboxBeginExtend %W [%W index @%x,%y]
  2334. }
  2335. bind Listbox <Control-1> {
  2336.     tkListboxBeginToggle %W [%W index @%x,%y]
  2337. }
  2338. bind Listbox <B1-Leave> {
  2339.     set tkPriv(x) %x
  2340.     set tkPriv(y) %y
  2341.     tkListboxAutoScan %W
  2342. }
  2343. bind Listbox <B1-Enter> {
  2344.     tkCancelRepeat
  2345. }
  2346.  
  2347. bind Listbox <Up> {
  2348.     tkListboxUpDown %W -1
  2349. }
  2350. bind Listbox <Shift-Up> {
  2351.     tkListboxExtendUpDown %W -1
  2352. }
  2353. bind Listbox <Down> {
  2354.     tkListboxUpDown %W 1
  2355. }
  2356. bind Listbox <Shift-Down> {
  2357.     tkListboxExtendUpDown %W 1
  2358. }
  2359. bind Listbox <Left> {
  2360.     %W xview scroll -1 units
  2361. }
  2362. bind Listbox <Control-Left> {
  2363.     %W xview scroll -1 pages
  2364. }
  2365. bind Listbox <Right> {
  2366.     %W xview scroll 1 units
  2367. }
  2368. bind Listbox <Control-Right> {
  2369.     %W xview scroll 1 pages
  2370. }
  2371. bind Listbox <Prior> {
  2372.     %W yview scroll -1 pages
  2373.     %W activate @0,0
  2374. }
  2375. bind Listbox <Next> {
  2376.     %W yview scroll 1 pages
  2377.     %W activate @0,0
  2378. }
  2379. bind Listbox <Control-Prior> {
  2380.     %W xview scroll -1 pages
  2381. }
  2382. bind Listbox <Control-Next> {
  2383.     %W xview scroll 1 pages
  2384. }
  2385. bind Listbox <Home> {
  2386.     %W xview moveto 0
  2387. }
  2388. bind Listbox <End> {
  2389.     %W xview moveto 1
  2390. }
  2391. bind Listbox <Control-Home> {
  2392.     %W activate 0
  2393.     %W see 0
  2394.     %W selection clear 0 end
  2395.     %W selection set 0
  2396. }
  2397. bind Listbox <Shift-Control-Home> {
  2398.     tkListboxDataExtend %W 0
  2399. }
  2400. bind Listbox <Control-End> {
  2401.     %W activate end
  2402.     %W see end
  2403.     %W selection clear 0 end
  2404.     %W selection set end
  2405. }
  2406. bind Listbox <Shift-Control-End> {
  2407.     tkListboxDataExtend %W end
  2408. }
  2409. bind Listbox <F16> {
  2410.     if {[selection own -displayof %W] == "%W"} {
  2411.     clipboard clear -displayof %W
  2412.     clipboard append -displayof %W [selection get -displayof %W]
  2413.     }
  2414. }
  2415. bind Listbox <space> {
  2416.     tkListboxBeginSelect %W [%W index active]
  2417. }
  2418. bind Listbox <Select> {
  2419.     tkListboxBeginSelect %W [%W index active]
  2420. }
  2421. bind Listbox <Control-Shift-space> {
  2422.     tkListboxBeginExtend %W [%W index active]
  2423. }
  2424. bind Listbox <Shift-Select> {
  2425.     tkListboxBeginExtend %W [%W index active]
  2426. }
  2427. bind Listbox <Escape> {
  2428.     tkListboxCancel %W
  2429. }
  2430. bind Listbox <Control-slash> {
  2431.     tkListboxSelectAll %W
  2432. }
  2433. bind Listbox <Control-backslash> {
  2434.     if {[%W cget -selectmode] != "browse"} {
  2435.     %W selection clear 0 end
  2436.     }
  2437. }
  2438.  
  2439. # Additional Tk bindings that aren't part of the Motif look and feel:
  2440.  
  2441. bind Listbox <2> {
  2442.     %W scan mark %x %y
  2443. }
  2444. bind Listbox <B2-Motion> {
  2445.     %W scan dragto %x %y
  2446. }
  2447.  
  2448. # tkListboxBeginSelect --
  2449. #
  2450. # This procedure is typically invoked on button-1 presses.  It begins
  2451. # the process of making a selection in the listbox.  Its exact behavior
  2452. # depends on the selection mode currently in effect for the listbox;
  2453. # see the Motif documentation for details.
  2454. #
  2455. # Arguments:
  2456. # w -        The listbox widget.
  2457. # el -        The element for the selection operation (typically the
  2458. #        one under the pointer).  Must be in numerical form.
  2459.  
  2460. proc tkListboxBeginSelect {w el} {
  2461.     global tkPriv
  2462.     if {[$w cget -selectmode]  == "multiple"} {
  2463.     if [$w selection includes $el] {
  2464.         $w selection clear $el
  2465.     } else {
  2466.         $w selection set $el
  2467.     }
  2468.     } else {
  2469.     $w selection clear 0 end
  2470.     $w selection set $el
  2471.     $w selection anchor $el
  2472.     set tkPriv(listboxSelection) {}
  2473.     set tkPriv(listboxPrev) $el
  2474.     }
  2475. }
  2476.  
  2477. # tkListboxMotion --
  2478. #
  2479. # This procedure is called to process mouse motion events while
  2480. # button 1 is down.  It may move or extend the selection, depending
  2481. # on the listbox's selection mode.
  2482. #
  2483. # Arguments:
  2484. # w -        The listbox widget.
  2485. # el -        The element under the pointer (must be a number).
  2486.  
  2487. proc tkListboxMotion {w el} {
  2488.     global tkPriv
  2489.     if {$el == $tkPriv(listboxPrev)} {
  2490.     return
  2491.     }
  2492.     set anchor [$w index anchor]
  2493.     switch [$w cget -selectmode] {
  2494.     browse {
  2495.         $w selection clear 0 end
  2496.         $w selection set $el
  2497.         set tkPriv(listboxPrev) $el
  2498.     }
  2499.     extended {
  2500.         set i $tkPriv(listboxPrev)
  2501.         if [$w selection includes anchor] {
  2502.         $w selection clear $i $el
  2503.         $w selection set anchor $el
  2504.         } else {
  2505.         $w selection clear $i $el
  2506.         $w selection clear anchor $el
  2507.         }
  2508.         while {($i < $el) && ($i < $anchor)} {
  2509.         if {[lsearch $tkPriv(listboxSelection) $i] >= 0} {
  2510.             $w selection set $i
  2511.         }
  2512.         incr i
  2513.         }
  2514.         while {($i > $el) && ($i > $anchor)} {
  2515.         if {[lsearch $tkPriv(listboxSelection) $i] >= 0} {
  2516.             $w selection set $i
  2517.         }
  2518.         incr i -1
  2519.         }
  2520.         set tkPriv(listboxPrev) $el
  2521.     }
  2522.     }
  2523. }
  2524.  
  2525. # tkListboxBeginExtend --
  2526. #
  2527. # This procedure is typically invoked on shift-button-1 presses.  It
  2528. # begins the process of extending a selection in the listbox.  Its
  2529. # exact behavior depends on the selection mode currently in effect
  2530. # for the listbox;  see the Motif documentation for details.
  2531. #
  2532. # Arguments:
  2533. # w -        The listbox widget.
  2534. # el -        The element for the selection operation (typically the
  2535. #        one under the pointer).  Must be in numerical form.
  2536.  
  2537. proc tkListboxBeginExtend {w el} {
  2538.     if {([$w cget -selectmode] == "extended")
  2539.         && [$w selection includes anchor]} {
  2540.     tkListboxMotion $w $el
  2541.     }
  2542. }
  2543.  
  2544. # tkListboxBeginToggle --
  2545. #
  2546. # This procedure is typically invoked on control-button-1 presses.  It
  2547. # begins the process of toggling a selection in the listbox.  Its
  2548. # exact behavior depends on the selection mode currently in effect
  2549. # for the listbox;  see the Motif documentation for details.
  2550. #
  2551. # Arguments:
  2552. # w -        The listbox widget.
  2553. # el -        The element for the selection operation (typically the
  2554. #        one under the pointer).  Must be in numerical form.
  2555.  
  2556. proc tkListboxBeginToggle {w el} {
  2557.     global tkPriv
  2558.     if {[$w cget -selectmode] == "extended"} {
  2559.     set tkPriv(listboxSelection) [$w curselection]
  2560.     set tkPriv(listboxPrev) $el
  2561.     $w selection anchor $el
  2562.     if [$w selection includes $el] {
  2563.         $w selection clear $el
  2564.     } else {
  2565.         $w selection set $el
  2566.     }
  2567.     }
  2568. }
  2569.  
  2570. # tkListboxAutoScan --
  2571. # This procedure is invoked when the mouse leaves an entry window
  2572. # with button 1 down.  It scrolls the window up, down, left, or
  2573. # right, depending on where the mouse left the window, and reschedules
  2574. # itself as an "after" command so that the window continues to scroll until
  2575. # the mouse moves back into the window or the mouse button is released.
  2576. #
  2577. # Arguments:
  2578. # w -        The entry window.
  2579.  
  2580. proc tkListboxAutoScan {w} {
  2581.     global tkPriv
  2582.     set x $tkPriv(x)
  2583.     set y $tkPriv(y)
  2584.     if {$y >= [winfo height $w]} {
  2585.     $w yview scroll 1 units
  2586.     } elseif {$y < 0} {
  2587.     $w yview scroll -1 units
  2588.     } elseif {$x >= [winfo width $w]} {
  2589.     $w xview scroll 2 units
  2590.     } elseif {$x < 0} {
  2591.     $w xview scroll -2 units
  2592.     } else {
  2593.     return
  2594.     }
  2595.     tkListboxMotion $w [$w index @$x,$y]
  2596.     set tkPriv(afterId) [after 50 tkListboxAutoScan $w]
  2597. }
  2598.  
  2599. # tkListboxUpDown --
  2600. #
  2601. # Moves the location cursor (active element) up or down by one element,
  2602. # and changes the selection if we're in browse or extended selection
  2603. # mode.
  2604. #
  2605. # Arguments:
  2606. # w -        The listbox widget.
  2607. # amount -    +1 to move down one item, -1 to move back one item.
  2608.  
  2609. proc tkListboxUpDown {w amount} {
  2610.     global tkPriv
  2611.     $w activate [expr [$w index active] + $amount]
  2612.     $w see active
  2613.     switch [$w cget -selectmode] {
  2614.     browse {
  2615.         $w selection clear 0 end
  2616.         $w selection set active
  2617.     }
  2618.     extended {
  2619.         $w selection clear 0 end
  2620.         $w selection set active
  2621.         $w selection anchor active
  2622.         set tkPriv(listboxPrev) [$w index active]
  2623.         set tkPriv(listboxSelection) {}
  2624.     }
  2625.     }
  2626. }
  2627.  
  2628. # tkListboxExtendUpDown --
  2629. #
  2630. # Does nothing unless we're in extended selection mode;  in this
  2631. # case it moves the location cursor (active element) up or down by
  2632. # one element, and extends the selection to that point.
  2633. #
  2634. # Arguments:
  2635. # w -        The listbox widget.
  2636. # amount -    +1 to move down one item, -1 to move back one item.
  2637.  
  2638. proc tkListboxExtendUpDown {w amount} {
  2639.     if {[$w cget -selectmode] != "extended"} {
  2640.     return
  2641.     }
  2642.     $w activate [expr [$w index active] + $amount]
  2643.     $w see active
  2644.     tkListboxMotion $w [$w index active]
  2645. }
  2646.  
  2647. # tkListboxDataExtend
  2648. #
  2649. # This procedure is called for key-presses such as Shift-KEndData.
  2650. # If the selection mode isn't multiple or extend then it does nothing.
  2651. # Otherwise it moves the active element to el and, if we're in
  2652. # extended mode, extends the selection to that point.
  2653. #
  2654. # Arguments:
  2655. # w -        The listbox widget.
  2656. # el -        An integer element number.
  2657.  
  2658. proc tkListboxDataExtend {w el} {
  2659.     set mode [$w cget -selectmode]
  2660.     if {$mode == "extended"} {
  2661.     $w activate $el
  2662.     $w see $el
  2663.         if [$w selection includes anchor] {
  2664.         tkListboxMotion $w $el
  2665.     }
  2666.     } elseif {$mode == "multiple"} {
  2667.     $w activate $el
  2668.     $w see $el
  2669.     }
  2670. }
  2671.  
  2672. # tkListboxCancel
  2673. #
  2674. # This procedure is invoked to cancel an extended selection in
  2675. # progress.  If there is an extended selection in progress, it
  2676. # restores all of the items between the active one and the anchor
  2677. # to their previous selection state.
  2678. #
  2679. # Arguments:
  2680. # w -        The listbox widget.
  2681.  
  2682. proc tkListboxCancel w {
  2683.     global tkPriv
  2684.     if {[$w cget -selectmode] != "extended"} {
  2685.     return
  2686.     }
  2687.     set first [$w index anchor]
  2688.     set last $tkPriv(listboxPrev)
  2689.     if {$first > $last} {
  2690.     set tmp $first
  2691.     set first $last
  2692.     set last $tmp
  2693.     }
  2694.     $w selection clear $first $last
  2695.     while {$first <= $last} {
  2696.     if {[lsearch $tkPriv(listboxSelection) $first] >= 0} {
  2697.         $w selection set $first
  2698.     }
  2699.     incr first
  2700.     }
  2701. }
  2702.  
  2703. # tkListboxSelectAll
  2704. #
  2705. # This procedure is invoked to handle the "select all" operation.
  2706. # For single and browse mode, it just selects the active element.
  2707. # Otherwise it selects everything in the widget.
  2708. #
  2709. # Arguments:
  2710. # w -        The listbox widget.
  2711.  
  2712. proc tkListboxSelectAll w {
  2713.     set mode [$w cget -selectmode]
  2714.     if {($mode == "single") || ($mode == "browse")} {
  2715.     $w selection clear 0 end
  2716.     $w selection set active
  2717.     } else {
  2718.     $w selection set 0 end
  2719.     }
  2720. }
  2721. #@package: library/tk tkCancelRepeat tkScreenChanged
  2722.  
  2723. # tk.tcl --
  2724. #
  2725. # Initialization script normally executed in the interpreter for each
  2726. # Tk-based application.  Arranges class bindings for widgets.
  2727. #
  2728. # @(#) tk.tcl 1.74 95/10/04 15:51:46
  2729. #
  2730. # Copyright (c) 1992-1994 The Regents of the University of California.
  2731. # Copyright (c) 1994-1995 Sun Microsystems, Inc.
  2732. #
  2733. # See the file "license.terms" for information on usage and redistribution
  2734. # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  2735.  
  2736. # Insist on running with compatible versions of Tcl and Tk.
  2737.  
  2738. scan [info tclversion] "%d.%d" a b
  2739. if {$a != 7} {
  2740.     error "wrong version of Tcl loaded ([info tclversion]): need 7.x"
  2741. }
  2742. scan $tk_version "%d.%d" a b
  2743. if {($a != 4) || ($b < 0)} {
  2744.     error "wrong version of Tk loaded ($tk_version): need 4.x"
  2745. }
  2746. unset a b
  2747.  
  2748. # Add Tk's directory to the end of the auto-load search path:
  2749.  
  2750. lappend auto_path $tk_library
  2751.  
  2752. # Turn off strict Motif look and feel as a default.
  2753.  
  2754. set tk_strictMotif 0
  2755.  
  2756. # tkScreenChanged --
  2757. # This procedure is invoked by the binding mechanism whenever the
  2758. # "current" screen is changing.  The procedure does two things.
  2759. # First, it uses "upvar" to make global variable "tkPriv" point at an
  2760. # array variable that holds state for the current display.  Second,
  2761. # it initializes the array if it didn't already exist.
  2762. #
  2763. # Arguments:
  2764. # screen -        The name of the new screen.
  2765.  
  2766. proc tkScreenChanged screen {
  2767.     set disp [file rootname $screen]
  2768.     uplevel #0 upvar #0 tkPriv.$disp tkPriv
  2769.     global tkPriv
  2770.     if [info exists tkPriv] {
  2771.     set tkPriv(screen) $screen
  2772.     return
  2773.     }
  2774.     set tkPriv(afterId) {}
  2775.     set tkPriv(buttons) 0
  2776.     set tkPriv(buttonWindow) {}
  2777.     set tkPriv(dragging) 0
  2778.     set tkPriv(focus) {}
  2779.     set tkPriv(grab) {}
  2780.     set tkPriv(initPos) {}
  2781.     set tkPriv(inMenubutton) {}
  2782.     set tkPriv(listboxPrev) {}
  2783.     set tkPriv(mouseMoved) 0
  2784.     set tkPriv(oldGrab) {}
  2785.     set tkPriv(popup) {}
  2786.     set tkPriv(postedMb) {}
  2787.     set tkPriv(pressX) 0
  2788.     set tkPriv(pressY) 0
  2789.     set tkPriv(screen) $screen
  2790.     set tkPriv(selectMode) char
  2791.     set tkPriv(window) {}
  2792. }
  2793.  
  2794. # Do initial setup for tkPriv, so that it is always bound to something
  2795. # (otherwise, if someone references it, it may get set to a non-upvar-ed
  2796. # value, which will cause trouble later).
  2797.  
  2798. tkScreenChanged [winfo screen .]
  2799.  
  2800. # ----------------------------------------------------------------------
  2801. # Read in files that define all of the class bindings.
  2802. # ----------------------------------------------------------------------
  2803.  
  2804. catch {source $tk_library/button.tcl}
  2805. catch {source $tk_library/entry.tcl}
  2806. catch {source $tk_library/listbox.tcl}
  2807. catch {source $tk_library/menu.tcl}
  2808. catch {source $tk_library/scale.tcl}
  2809. catch {source $tk_library/scrlbar.tcl}
  2810. catch {source $tk_library/text.tcl}
  2811.  
  2812. # ----------------------------------------------------------------------
  2813. # Default bindings for keyboard traversal.
  2814. # ----------------------------------------------------------------------
  2815.  
  2816. bind all <Tab> {focus [tk_focusNext %W]}
  2817. bind all <Shift-Tab> {focus [tk_focusPrev %W]}
  2818.  
  2819. # tkCancelRepeat --
  2820. # This procedure is invoked to cancel an auto-repeat action described
  2821. # by tkPriv(afterId).  It's used by several widgets to auto-scroll
  2822. # the widget when the mouse is dragged out of the widget with a
  2823. # button pressed.
  2824. #
  2825. # Arguments:
  2826. # None.
  2827.  
  2828. proc tkCancelRepeat {} {
  2829.     global tkPriv
  2830.     after cancel $tkPriv(afterId)
  2831.     set tkPriv(afterId) {}
  2832. }
  2833. #@package: library/dialog tk_dialog
  2834.  
  2835. # dialog.tcl --
  2836. #
  2837. # This file defines the procedure tk_dialog, which creates a dialog
  2838. # box containing a bitmap, a message, and one or more buttons.
  2839. #
  2840. # @(#) dialog.tcl 1.19 95/09/27 09:51:36
  2841. #
  2842. # Copyright (c) 1992-1993 The Regents of the University of California.
  2843. # Copyright (c) 1994-1995 Sun Microsystems, Inc.
  2844. #
  2845. # See the file "license.terms" for information on usage and redistribution
  2846. # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  2847. #
  2848.  
  2849. #
  2850. # tk_dialog:
  2851. #
  2852. # This procedure displays a dialog box, waits for a button in the dialog
  2853. # to be invoked, then returns the index of the selected button.
  2854. #
  2855. # Arguments:
  2856. # w -        Window to use for dialog top-level.
  2857. # title -    Title to display in dialog's decorative frame.
  2858. # text -    Message to display in dialog.
  2859. # bitmap -    Bitmap to display in dialog (empty string means none).
  2860. # default -    Index of button that is to display the default ring
  2861. #        (-1 means none).
  2862. # args -    One or more strings to display in buttons across the
  2863. #        bottom of the dialog box.
  2864.  
  2865. proc tk_dialog {w title text bitmap default args} {
  2866.     global tkPriv
  2867.  
  2868.     # 1. Create the top-level window and divide it into top
  2869.     # and bottom parts.
  2870.  
  2871.     catch {destroy $w}
  2872.     toplevel $w -class Dialog
  2873.     wm title $w $title
  2874.     wm iconname $w Dialog
  2875.     wm protocol $w WM_DELETE_WINDOW { }
  2876.     wm transient $w [winfo toplevel [winfo parent $w]]
  2877.     frame $w.top -relief raised -bd 1
  2878.     pack $w.top -side top -fill both
  2879.     frame $w.bot -relief raised -bd 1
  2880.     pack $w.bot -side bottom -fill both
  2881.  
  2882.     # 2. Fill the top part with bitmap and message (use the option
  2883.     # database for -wraplength so that it can be overridden by
  2884.     # the caller).
  2885.  
  2886.     option add *Dialog.msg.wrapLength 3i widgetDefault
  2887.     label $w.msg -justify left -text $text \
  2888.         -font -Adobe-Times-Medium-R-Normal--*-180-*-*-*-*-*-*
  2889.     pack $w.msg -in $w.top -side right -expand 1 -fill both -padx 3m -pady 3m
  2890.     if {$bitmap != ""} {
  2891.     label $w.bitmap -bitmap $bitmap
  2892.     pack $w.bitmap -in $w.top -side left -padx 3m -pady 3m
  2893.     }
  2894.  
  2895.     # 3. Create a row of buttons at the bottom of the dialog.
  2896.  
  2897.     set i 0
  2898.     foreach but $args {
  2899.     button $w.button$i -text $but -command "set tkPriv(button) $i"
  2900.     if {$i == $default} {
  2901.         frame $w.default -relief sunken -bd 1
  2902.         raise $w.button$i $w.default
  2903.         pack $w.default -in $w.bot -side left -expand 1 -padx 3m -pady 2m
  2904.         pack $w.button$i -in $w.default -padx 2m -pady 2m
  2905.         bind $w <Return> "$w.button$i flash; set tkPriv(button) $i"
  2906.     } else {
  2907.         pack $w.button$i -in $w.bot -side left -expand 1 \
  2908.             -padx 3m -pady 2m
  2909.     }
  2910.     incr i
  2911.     }
  2912.  
  2913.     # 4. Withdraw the window, then update all the geometry information
  2914.     # so we know how big it wants to be, then center the window in the
  2915.     # display and de-iconify it.
  2916.  
  2917.     wm withdraw $w
  2918.     update idletasks
  2919.     set x [expr [winfo screenwidth $w]/2 - [winfo reqwidth $w]/2 \
  2920.         - [winfo vrootx [winfo parent $w]]]
  2921.     set y [expr [winfo screenheight $w]/2 - [winfo reqheight $w]/2 \
  2922.         - [winfo vrooty [winfo parent $w]]]
  2923.     wm geom $w +$x+$y
  2924.     wm deiconify $w
  2925.  
  2926.     # 5. Set a grab and claim the focus too.
  2927.  
  2928.     set oldFocus [focus]
  2929.     set oldGrab [grab current $w]
  2930.     if {$oldGrab != ""} {
  2931.     set grabStatus [grab status $oldGrab]
  2932.     }
  2933.     grab $w
  2934.     if {$default >= 0} {
  2935.     focus $w.button$default
  2936.     } else {
  2937.     focus $w
  2938.     }
  2939.  
  2940.     # 6. Wait for the user to respond, then restore the focus and
  2941.     # return the index of the selected button.  Restore the focus
  2942.     # before deleting the window, since otherwise the window manager
  2943.     # may take the focus away so we can't redirect it.  Finally,
  2944.     # restore any grab that was in effect.
  2945.  
  2946.     tkwait variable tkPriv(button)
  2947.     catch {focus $oldFocus}
  2948.     destroy $w
  2949.     if {$oldGrab != ""} {
  2950.     if {$grabStatus == "global"} {
  2951.         grab -global $oldGrab
  2952.     } else {
  2953.         grab $oldGrab
  2954.     }
  2955.     }
  2956.     return $tkPriv(button)
  2957. }
  2958. #@package: library/tkerror tkerror
  2959.  
  2960. # tkerror.tcl --
  2961. #
  2962. # This file contains a default version of the tkError procedure.  It
  2963. # posts a dialog box with the error message and gives the user a chance
  2964. # to see a more detailed stack trace.
  2965. #
  2966. # @(#) tkerror.tcl 1.6 95/07/28 09:37:40
  2967. #
  2968. # Copyright (c) 1992-1994 The Regents of the University of California.
  2969. # Copyright (c) 1994-1995 Sun Microsystems, Inc.
  2970. #
  2971. # See the file "license.terms" for information on usage and redistribution
  2972. # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  2973.  
  2974. # tkerror --
  2975. # This is the default version of tkerror.  It posts a dialog box containing
  2976. # the error message and gives the user a chance to ask to see a stack
  2977. # trace.
  2978. # Arguments:
  2979. # err -            The error message.
  2980.  
  2981. proc tkerror err {
  2982.     global errorInfo
  2983.     set info $errorInfo
  2984.     set button [tk_dialog .tkerrorDialog "Error in Tcl Script" \
  2985.         "Error: $err" error 0 OK "Skip Messages" "Stack Trace"]
  2986.     if {$button == 0} {
  2987.     return
  2988.     } elseif {$button == 1} {
  2989.     return -code break
  2990.     }
  2991.  
  2992.     set w .tkerrorTrace
  2993.     catch {destroy $w}
  2994.     toplevel $w -class ErrorTrace
  2995.     wm minsize $w 1 1
  2996.     wm title $w "Stack Trace for Error"
  2997.     wm iconname $w "Stack Trace"
  2998.     button $w.ok -text OK -command "destroy $w"
  2999.     text $w.text -relief sunken -bd 2 -yscrollcommand "$w.scroll set" \
  3000.         -setgrid true -width 60 -height 20
  3001.     scrollbar $w.scroll -relief sunken -command "$w.text yview"
  3002.     pack $w.ok -side bottom -padx 3m -pady 2m
  3003.     pack $w.scroll -side right -fill y
  3004.     pack $w.text -side left -expand yes -fill both
  3005.     $w.text insert 0.0 $info
  3006.     $w.text mark set insert 0.0
  3007.  
  3008.     # Center the window on the screen.
  3009.  
  3010.     wm withdraw $w
  3011.     update idletasks
  3012.     set x [expr [winfo screenwidth $w]/2 - [winfo reqwidth $w]/2 \
  3013.         - [winfo vrootx [winfo parent $w]]]
  3014.     set y [expr [winfo screenheight $w]/2 - [winfo reqheight $w]/2 \
  3015.         - [winfo vrooty [winfo parent $w]]]
  3016.     wm geom $w +$x+$y
  3017.     wm deiconify $w
  3018.  
  3019.     # Be sure to release any grabs that might be present on the
  3020.     # screen, since they could make it impossible for the user
  3021.     # to interact with the stack trace.
  3022.  
  3023.     if {[grab current .] != ""} {
  3024.     grab release [grab current .]
  3025.     }
  3026. }
  3027. #@package: library/scrlbar tkScrollButtonUp tkScrollByPages tkScrollButtonDown tkScrollToPos tkScrollButton2Down tkScrollByUnits tkScrollDrag tkScrollEndDrag tkScrollSelect tkScrollStartDrag tkScrollTopBottom
  3028.  
  3029. # scrlbar.tcl --
  3030. #
  3031. # This file defines the default bindings for Tk scrollbar widgets.
  3032. # It also provides procedures that help in implementing the bindings.
  3033. #
  3034. # @(#) scrlbar.tcl 1.19 95/10/04 15:00:16
  3035. #
  3036. # Copyright (c) 1994 The Regents of the University of California.
  3037. # Copyright (c) 1994-1995 Sun Microsystems, Inc.
  3038. #
  3039. # See the file "license.terms" for information on usage and redistribution
  3040. # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  3041. #
  3042.  
  3043. #-------------------------------------------------------------------------
  3044. # The code below creates the default class bindings for scrollbars.
  3045. #-------------------------------------------------------------------------
  3046.  
  3047. # Standard Motif bindings:
  3048.  
  3049. bind Scrollbar <Enter> {
  3050.     if $tk_strictMotif {
  3051.     set tkPriv(activeBg) [%W cget -activebackground]
  3052.     %W config -activebackground [%W cget -background]
  3053.     }
  3054.     %W activate [%W identify %x %y]
  3055. }
  3056. bind Scrollbar <Motion> {
  3057.     %W activate [%W identify %x %y]
  3058. }
  3059. bind Scrollbar <Leave> {
  3060.     if $tk_strictMotif {
  3061.     %W config -activebackground $tkPriv(activeBg)
  3062.     }
  3063.     %W activate {}
  3064. }
  3065. bind Scrollbar <1> {
  3066.     tkScrollButtonDown %W %x %y
  3067. }
  3068. bind Scrollbar <B1-Motion> {
  3069.     tkScrollDrag %W %x %y
  3070. }
  3071. bind Scrollbar <B1-B2-Motion> {
  3072.     tkScrollDrag %W %x %y
  3073. }
  3074. bind Scrollbar <ButtonRelease-1> {
  3075.     tkScrollButtonUp %W %x %y
  3076. }
  3077. bind Scrollbar <B1-Leave> {
  3078.     # Prevents <Leave> binding from being invoked.
  3079. }
  3080. bind Scrollbar <B1-Enter> {
  3081.     # Prevents <Enter> binding from being invoked.
  3082. }
  3083. bind Scrollbar <2> {
  3084.     tkScrollButton2Down %W %x %y
  3085. }
  3086. bind Scrollbar <B1-2> {
  3087.     # Do nothing, since button 1 is already down.
  3088. }
  3089. bind Scrollbar <B2-1> {
  3090.     # Do nothing, since button 2 is already down.
  3091. }
  3092. bind Scrollbar <B2-Motion> {
  3093.     tkScrollDrag %W %x %y
  3094. }
  3095. bind Scrollbar <ButtonRelease-2> {
  3096.     tkScrollButtonUp %W %x %y
  3097. }
  3098. bind Scrollbar <B1-ButtonRelease-2> {
  3099.     # Do nothing:  B1 release will handle it.
  3100. }
  3101. bind Scrollbar <B2-ButtonRelease-1> {
  3102.     # Do nothing:  B2 release will handle it.
  3103. }
  3104. bind Scrollbar <B2-Leave> {
  3105.     # Prevents <Leave> binding from being invoked.
  3106. }
  3107. bind Scrollbar <B2-Enter> {
  3108.     # Prevents <Enter> binding from being invoked.
  3109. }
  3110. bind Scrollbar <Control-1> {
  3111.     tkScrollTopBottom %W %x %y
  3112. }
  3113. bind Scrollbar <Control-2> {
  3114.     tkScrollTopBottom %W %x %y
  3115. }
  3116.  
  3117. bind Scrollbar <Up> {
  3118.     tkScrollByUnits %W v -1
  3119. }
  3120. bind Scrollbar <Down> {
  3121.     tkScrollByUnits %W v 1
  3122. }
  3123. bind Scrollbar <Control-Up> {
  3124.     tkScrollByPages %W v -1
  3125. }
  3126. bind Scrollbar <Control-Down> {
  3127.     tkScrollByPages %W v 1
  3128. }
  3129. bind Scrollbar <Left> {
  3130.     tkScrollByUnits %W h -1
  3131. }
  3132. bind Scrollbar <Right> {
  3133.     tkScrollByUnits %W h 1
  3134. }
  3135. bind Scrollbar <Control-Left> {
  3136.     tkScrollByPages %W h -1
  3137. }
  3138. bind Scrollbar <Control-Right> {
  3139.     tkScrollByPages %W h 1
  3140. }
  3141. bind Scrollbar <Prior> {
  3142.     tkScrollByPages %W hv -1
  3143. }
  3144. bind Scrollbar <Next> {
  3145.     tkScrollByPages %W hv 1
  3146. }
  3147. bind Scrollbar <Home> {
  3148.     tkScrollToPos %W 0
  3149. }
  3150. bind Scrollbar <End> {
  3151.     tkScrollToPos %W 1
  3152. }
  3153.  
  3154. # tkScrollButtonDown --
  3155. # This procedure is invoked when a button is pressed in a scrollbar.
  3156. # It changes the way the scrollbar is displayed and takes actions
  3157. # depending on where the mouse is.
  3158. #
  3159. # Arguments:
  3160. # w -        The scrollbar widget.
  3161. # x, y -    Mouse coordinates.
  3162.  
  3163. proc tkScrollButtonDown {w x y} {
  3164.     global tkPriv
  3165.     set tkPriv(relief) [$w cget -activerelief]
  3166.     $w configure -activerelief sunken
  3167.     set element [$w identify $x $y]
  3168.     if {$element == "slider"} {
  3169.     tkScrollStartDrag $w $x $y
  3170.     } else {
  3171.     tkScrollSelect $w $element initial
  3172.     }
  3173. }
  3174.  
  3175. # tkScrollButtonUp --
  3176. # This procedure is invoked when a button is released in a scrollbar.
  3177. # It cancels scans and auto-repeats that were in progress, and restores
  3178. # the way the active element is displayed.
  3179. #
  3180. # Arguments:
  3181. # w -        The scrollbar widget.
  3182. # x, y -    Mouse coordinates.
  3183.  
  3184. proc tkScrollButtonUp {w x y} {
  3185.     global tkPriv
  3186.     tkCancelRepeat
  3187.     $w configure -activerelief $tkPriv(relief)
  3188.     tkScrollEndDrag $w $x $y
  3189.     $w activate [$w identify $x $y]
  3190. }
  3191.  
  3192. # tkScrollSelect --
  3193. # This procedure is invoked when a button is pressed over the scrollbar.
  3194. # It invokes one of several scrolling actions depending on where in
  3195. # the scrollbar the button was pressed.
  3196. #
  3197. # Arguments:
  3198. # w -        The scrollbar widget.
  3199. # element -    The element of the scrollbar that was selected, such
  3200. #        as "arrow1" or "trough2".  Shouldn't be "slider".
  3201. # repeat -    Whether and how to auto-repeat the action:  "noRepeat"
  3202. #        means don't auto-repeat, "initial" means this is the
  3203. #        first action in an auto-repeat sequence, and "again"
  3204. #        means this is the second repetition or later.
  3205.  
  3206. proc tkScrollSelect {w element repeat} {
  3207.     global tkPriv
  3208.     if {$element == "arrow1"} {
  3209.     tkScrollByUnits $w hv -1
  3210.     } elseif {$element == "trough1"} {
  3211.     tkScrollByPages $w hv -1
  3212.     } elseif {$element == "trough2"} {
  3213.     tkScrollByPages $w hv 1
  3214.     } elseif {$element == "arrow2"} {
  3215.     tkScrollByUnits $w hv 1
  3216.     } else {
  3217.     return
  3218.     }
  3219.     if {$repeat == "again"} {
  3220.     set tkPriv(afterId) [after [$w cget -repeatinterval] \
  3221.         tkScrollSelect $w $element again]
  3222.     } elseif {$repeat == "initial"} {
  3223.     set delay [$w cget -repeatdelay]
  3224.     if {$delay > 0} {
  3225.         set tkPriv(afterId) [after $delay tkScrollSelect $w $element again]
  3226.     }
  3227.     }
  3228. }
  3229.  
  3230. # tkScrollStartDrag --
  3231. # This procedure is called to initiate a drag of the slider.  It just
  3232. # remembers the starting position of the mouse and slider.
  3233. #
  3234. # Arguments:
  3235. # w -        The scrollbar widget.
  3236. # x, y -    The mouse position at the start of the drag operation.
  3237.  
  3238. proc tkScrollStartDrag {w x y} {
  3239.     global tkPriv
  3240.  
  3241.     if {[$w cget -command] == ""} {
  3242.     return
  3243.     }
  3244.     set tkPriv(pressX) $x
  3245.     set tkPriv(pressY) $y
  3246.     set tkPriv(initValues) [$w get]
  3247.     set iv0 [lindex $tkPriv(initValues) 0]
  3248.     if {[llength $tkPriv(initValues)] == 2} {
  3249.     set tkPriv(initPos) $iv0
  3250.     } else {
  3251.     if {$iv0 == 0} {
  3252.         set tkPriv(initPos) 0.0
  3253.     } else {
  3254.         set tkPriv(initPos) [expr (double([lindex $tkPriv(initValues) 2])) \
  3255.             / [lindex $tkPriv(initValues) 0]]
  3256.     }
  3257.     }
  3258. }
  3259.  
  3260. # tkScrollDrag --
  3261. # This procedure is called for each mouse motion even when the slider
  3262. # is being dragged.  It notifies the associated widget if we're not
  3263. # jump scrolling, and it just updates the scrollbar if we are jump
  3264. # scrolling.
  3265. #
  3266. # Arguments:
  3267. # w -        The scrollbar widget.
  3268. # x, y -    The current mouse position.
  3269.  
  3270. proc tkScrollDrag {w x y} {
  3271.     global tkPriv
  3272.  
  3273.     if {$tkPriv(initPos) == ""} {
  3274.     return
  3275.     }
  3276.     set delta [$w delta [expr $x - $tkPriv(pressX)] [expr $y - $tkPriv(pressY)]]
  3277.     if [$w cget -jump] {
  3278.     if {[llength $tkPriv(initValues)] == 2} {
  3279.         $w set [expr [lindex $tkPriv(initValues) 0] + $delta] \
  3280.             [expr [lindex $tkPriv(initValues) 1] + $delta]
  3281.     } else {
  3282.         set delta [expr round($delta * [lindex $tkPriv(initValues) 0])]
  3283.         eval $w set [lreplace $tkPriv(initValues) 2 3 \
  3284.             [expr [lindex $tkPriv(initValues) 2] + $delta] \
  3285.             [expr [lindex $tkPriv(initValues) 3] + $delta]]
  3286.     }
  3287.     } else {
  3288.     tkScrollToPos $w [expr $tkPriv(initPos) + $delta]
  3289.     }
  3290. }
  3291.  
  3292. # tkScrollEndDrag --
  3293. # This procedure is called to end an interactive drag of the slider.
  3294. # It scrolls the window if we're in jump mode, otherwise it does nothing.
  3295. #
  3296. # Arguments:
  3297. # w -        The scrollbar widget.
  3298. # x, y -    The mouse position at the end of the drag operation.
  3299.  
  3300. proc tkScrollEndDrag {w x y} {
  3301.     global tkPriv
  3302.  
  3303.     if {$tkPriv(initPos) == ""} {
  3304.     return
  3305.     }
  3306.     if [$w cget -jump] {
  3307.     set delta [$w delta [expr $x - $tkPriv(pressX)] \
  3308.         [expr $y - $tkPriv(pressY)]]
  3309.     tkScrollToPos $w [expr $tkPriv(initPos) + $delta]
  3310.     }
  3311.     set tkPriv(initPos) ""
  3312. }
  3313.  
  3314. # tkScrollByUnits --
  3315. # This procedure tells the scrollbar's associated widget to scroll up
  3316. # or down by a given number of units.  It notifies the associated widget
  3317. # in different ways for old and new command syntaxes.
  3318. #
  3319. # Arguments:
  3320. # w -        The scrollbar widget.
  3321. # orient -    Which kinds of scrollbars this applies to:  "h" for
  3322. #        horizontal, "v" for vertical, "hv" for both.
  3323. # amount -    How many units to scroll:  typically 1 or -1.
  3324.  
  3325. proc tkScrollByUnits {w orient amount} {
  3326.     set cmd [$w cget -command]
  3327.     if {($cmd == "") || ([string first \
  3328.         [string index [$w cget -orient] 0] $orient] < 0)} {
  3329.     return
  3330.     }
  3331.     set info [$w get]
  3332.     if {[llength $info] == 2} {
  3333.     uplevel #0 $cmd scroll $amount units
  3334.     } else {
  3335.     uplevel #0 $cmd [expr [lindex $info 2] + $amount]
  3336.     }
  3337. }
  3338.  
  3339. # tkScrollByPages --
  3340. # This procedure tells the scrollbar's associated widget to scroll up
  3341. # or down by a given number of screenfuls.  It notifies the associated
  3342. # widget in different ways for old and new command syntaxes.
  3343. #
  3344. # Arguments:
  3345. # w -        The scrollbar widget.
  3346. # orient -    Which kinds of scrollbars this applies to:  "h" for
  3347. #        horizontal, "v" for vertical, "hv" for both.
  3348. # amount -    How many screens to scroll:  typically 1 or -1.
  3349.  
  3350. proc tkScrollByPages {w orient amount} {
  3351.     set cmd [$w cget -command]
  3352.     if {($cmd == "") || ([string first \
  3353.         [string index [$w cget -orient] 0] $orient] < 0)} {
  3354.     return
  3355.     }
  3356.     set info [$w get]
  3357.     if {[llength $info] == 2} {
  3358.     uplevel #0 $cmd scroll $amount pages
  3359.     } else {
  3360.     uplevel #0 $cmd [expr [lindex $info 2] + $amount*([lindex $info 1] - 1)]
  3361.     }
  3362. }
  3363.  
  3364. # tkScrollToPos --
  3365. # This procedure tells the scrollbar's associated widget to scroll to
  3366. # a particular location, given by a fraction between 0 and 1.  It notifies
  3367. # the associated widget in different ways for old and new command syntaxes.
  3368. #
  3369. # Arguments:
  3370. # w -        The scrollbar widget.
  3371. # pos -        A fraction between 0 and 1 indicating a desired position
  3372. #        in the document.
  3373.  
  3374. proc tkScrollToPos {w pos} {
  3375.     set cmd [$w cget -command]
  3376.     if {($cmd == "")} {
  3377.     return
  3378.     }
  3379.     set info [$w get]
  3380.     if {[llength $info] == 2} {
  3381.     uplevel #0 $cmd moveto $pos
  3382.     } else {
  3383.     uplevel #0 $cmd [expr round([lindex $info 0]*$pos)]
  3384.     }
  3385. }
  3386.  
  3387. # tkScrollTopBottom
  3388. # Scroll to the top or bottom of the document, depending on the mouse
  3389. # position.
  3390. #
  3391. # Arguments:
  3392. # w -        The scrollbar widget.
  3393. # x, y -    Mouse coordinates within the widget.
  3394.  
  3395. proc tkScrollTopBottom {w x y} {
  3396.     set element [$w identify $x $y]
  3397.     if [string match *1 $element] {
  3398.     tkScrollToPos $w 0
  3399.     } elseif [string match *2 $element] {
  3400.     tkScrollToPos $w 1
  3401.     }
  3402. }
  3403.  
  3404. # tkScrollButton2Down
  3405. # This procedure is invoked when button 2 is pressed over a scrollbar.
  3406. # If the button is over the trough or slider, it sets the scrollbar to
  3407. # the mouse position and starts a slider drag.  Otherwise it just
  3408. # behaves the same as button 1.
  3409. #
  3410. # Arguments:
  3411. # w -        The scrollbar widget.
  3412. # x, y -    Mouse coordinates within the widget.
  3413.  
  3414. proc tkScrollButton2Down {w x y} {
  3415.     global tkPriv
  3416.     set element [$w identify $x $y]
  3417.     if {($element == "arrow1") || ($element == "arrow2")} {
  3418.     tkScrollButtonDown $w $x $y
  3419.     return
  3420.     }
  3421.     tkScrollToPos $w [$w fraction $x $y]
  3422.  
  3423.     # Need the "update idletasks" below so that the widget calls us
  3424.     # back to reset the actual scrollbar position before we start the
  3425.     # slider drag.
  3426.  
  3427.     update idletasks
  3428.     set tkPriv(relief) [$w cget -activerelief]
  3429.     $w configure -activerelief sunken
  3430.     $w activate slider
  3431.     tkScrollStartDrag $w $x $y
  3432. }
  3433. #@package: library/button tkCheckRadioInvoke tkButtonInvoke tkButtonDown tkButtonEnter tkButtonUp tkButtonLeave
  3434.  
  3435. # button.tcl --
  3436. #
  3437. # This file defines the default bindings for Tk label, button,
  3438. # checkbutton, and radiobutton widgets and provides procedures
  3439. # that help in implementing those bindings.
  3440. #
  3441. # @(#) button.tcl 1.17 95/05/05 16:56:01
  3442. #
  3443. # Copyright (c) 1992-1994 The Regents of the University of California.
  3444. # Copyright (c) 1994 Sun Microsystems, Inc.
  3445. #
  3446. # See the file "license.terms" for information on usage and redistribution
  3447. # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  3448. #
  3449.  
  3450. #-------------------------------------------------------------------------
  3451. # The code below creates the default class bindings for buttons.
  3452. #-------------------------------------------------------------------------
  3453.  
  3454. bind Button <FocusIn> {}
  3455. bind Button <Enter> {
  3456.     tkButtonEnter %W
  3457. }
  3458. bind Button <Leave> {
  3459.     tkButtonLeave %W
  3460. }
  3461. bind Button <1> {
  3462.     tkButtonDown %W
  3463. }
  3464. bind Button <ButtonRelease-1> {
  3465.     tkButtonUp %W
  3466. }
  3467. bind Button <space> {
  3468.     tkButtonInvoke %W
  3469. }
  3470. bind Button <Return> {
  3471.     if !$tk_strictMotif {
  3472.     tkButtonInvoke %W
  3473.     }
  3474. }
  3475.  
  3476. bind Checkbutton <FocusIn> {}
  3477. bind Checkbutton <Enter> {
  3478.     tkButtonEnter %W
  3479. }
  3480. bind Checkbutton <Leave> {
  3481.     tkButtonLeave %W
  3482. }
  3483. bind Checkbutton <1> {
  3484.     tkCheckRadioInvoke %W
  3485. }
  3486. bind Checkbutton <space> {
  3487.     tkCheckRadioInvoke %W
  3488. }
  3489. bind Checkbutton <Return> {
  3490.     if !$tk_strictMotif {
  3491.     tkCheckRadioInvoke %W
  3492.     }
  3493. }
  3494.  
  3495. bind Radiobutton <FocusIn> {}
  3496. bind Radiobutton <Enter> {
  3497.     tkButtonEnter %W
  3498. }
  3499. bind Radiobutton <Leave> {
  3500.     tkButtonLeave %W
  3501. }
  3502. bind Radiobutton <1> {
  3503.     tkCheckRadioInvoke %W
  3504. }
  3505. bind Radiobutton <space> {
  3506.     tkCheckRadioInvoke %W
  3507. }
  3508. bind Radiobutton <Return> {
  3509.     if !$tk_strictMotif {
  3510.     tkCheckRadioInvoke %W
  3511.     }
  3512. }
  3513.  
  3514. # tkButtonEnter --
  3515. # The procedure below is invoked when the mouse pointer enters a
  3516. # button widget.  It records the button we're in and changes the
  3517. # state of the button to active unless the button is disabled.
  3518. #
  3519. # Arguments:
  3520. # w -        The name of the widget.
  3521.  
  3522. proc tkButtonEnter {w} {
  3523.     global tkPriv
  3524.     if {[$w cget -state] != "disabled"} {
  3525.     $w config -state active
  3526.     if {$tkPriv(buttonWindow) == $w} {
  3527.         $w configure -state active -relief sunken
  3528.     }
  3529.     }
  3530.     set tkPriv(window) $w
  3531. }
  3532.  
  3533. # tkButtonLeave --
  3534. # The procedure below is invoked when the mouse pointer leaves a
  3535. # button widget.  It changes the state of the button back to
  3536. # inactive.  If we're leaving the button window with a mouse button
  3537. # pressed (tkPriv(buttonWindow) == $w), restore the relief of the
  3538. # button too.
  3539. #
  3540. # Arguments:
  3541. # w -        The name of the widget.
  3542.  
  3543. proc tkButtonLeave w {
  3544.     global tkPriv
  3545.     if {[$w cget -state] != "disabled"} {
  3546.     $w config -state normal
  3547.     }
  3548.     if {$w == $tkPriv(buttonWindow)} {
  3549.     $w configure -relief $tkPriv(relief)
  3550.     }
  3551.     set tkPriv(window) ""
  3552. }
  3553.  
  3554. # tkButtonDown --
  3555. # The procedure below is invoked when the mouse button is pressed in
  3556. # a button widget.  It records the fact that the mouse is in the button,
  3557. # saves the button's relief so it can be restored later, and changes
  3558. # the relief to sunken.
  3559. #
  3560. # Arguments:
  3561. # w -        The name of the widget.
  3562.  
  3563. proc tkButtonDown w {
  3564.     global tkPriv
  3565.     set tkPriv(relief) [lindex [$w config -relief] 4]
  3566.     if {[$w cget -state] != "disabled"} {
  3567.     set tkPriv(buttonWindow) $w
  3568.     $w config -relief sunken
  3569.     }
  3570. }
  3571.  
  3572. # tkButtonUp --
  3573. # The procedure below is invoked when the mouse button is released
  3574. # in a button widget.  It restores the button's relief and invokes
  3575. # the command as long as the mouse hasn't left the button.
  3576. #
  3577. # Arguments:
  3578. # w -        The name of the widget.
  3579.  
  3580. proc tkButtonUp w {
  3581.     global tkPriv
  3582.     if {$w == $tkPriv(buttonWindow)} {
  3583.     set tkPriv(buttonWindow) ""
  3584.     $w config -relief $tkPriv(relief)
  3585.     if {($w == $tkPriv(window))
  3586.         && ([$w cget -state] != "disabled")} {
  3587.         uplevel #0 [list $w invoke]
  3588.     }
  3589.     }
  3590. }
  3591.  
  3592. # tkButtonInvoke --
  3593. # The procedure below is called when a button is invoked through
  3594. # the keyboard.  It simulate a press of the button via the mouse.
  3595. #
  3596. # Arguments:
  3597. # w -        The name of the widget.
  3598.  
  3599. proc tkButtonInvoke w {
  3600.     if {[$w cget -state] != "disabled"} {
  3601.     set oldRelief [$w cget -relief]
  3602.     set oldState [$w cget -state]
  3603.     $w configure -state active -relief sunken
  3604.     update idletasks
  3605.     after 100
  3606.     $w configure -state $oldState -relief $oldRelief
  3607.     uplevel #0 [list $w invoke]
  3608.     }
  3609. }
  3610.  
  3611. # tkCheckRadioInvoke --
  3612. # The procedure below is invoked when the mouse button is pressed in
  3613. # a checkbutton or radiobutton widget, or when the widget is invoked
  3614. # through the keyboard.  It invokes the widget if it
  3615. # isn't disabled.
  3616. #
  3617. # Arguments:
  3618. # w -        The name of the widget.
  3619.  
  3620. proc tkCheckRadioInvoke w {
  3621.     if {[$w cget -state] != "disabled"} {
  3622.     uplevel #0 [list $w invoke]
  3623.     }
  3624. }
  3625. #@package: library/text tkTextKeySelect tkTextSetCursor tkTextClipboardKeysyms tkTextTranspose tkTextScrollPages tkTextKeyExtend tkTextSelectTo tkTextPrevPara tkTextUpDownLine tkTextButton1 tkTextNextPara tkTextResetAnchor tkTextAutoScan
  3626.  
  3627. # text.tcl --
  3628. #
  3629. # This file defines the default bindings for Tk text widgets and provides
  3630. # procedures that help in implementing the bindings.
  3631. #
  3632. # @(#) text.tcl 1.36 95/06/28 10:24:23
  3633. #
  3634. # Copyright (c) 1992-1994 The Regents of the University of California.
  3635. # Copyright (c) 1994-1995 Sun Microsystems, Inc.
  3636. #
  3637. # See the file "license.terms" for information on usage and redistribution
  3638. # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  3639. #
  3640.  
  3641. #-------------------------------------------------------------------------
  3642. # Elements of tkPriv that are used in this file:
  3643. #
  3644. # afterId -        If non-null, it means that auto-scanning is underway
  3645. #            and it gives the "after" id for the next auto-scan
  3646. #            command to be executed.
  3647. # char -        Character position on the line;  kept in order
  3648. #            to allow moving up or down past short lines while
  3649. #            still remembering the desired position.
  3650. # mouseMoved -        Non-zero means the mouse has moved a significant
  3651. #            amount since the button went down (so, for example,
  3652. #            start dragging out a selection).
  3653. # prevPos -        Used when moving up or down lines via the keyboard.
  3654. #            Keeps track of the previous insert position, so
  3655. #            we can distinguish a series of ups and downs, all
  3656. #            in a row, from a new up or down.
  3657. # selectMode -        The style of selection currently underway:
  3658. #            char, word, or line.
  3659. # x, y -        Last known mouse coordinates for scanning
  3660. #            and auto-scanning.
  3661. #-------------------------------------------------------------------------
  3662.  
  3663. # tkTextClipboardKeysyms --
  3664. # This procedure is invoked to identify the keys that correspond to
  3665. # the "copy", "cut", and "paste" functions for the clipboard.
  3666. #
  3667. # Arguments:
  3668. # copy -    Name of the key (keysym name plus modifiers, if any,
  3669. #        such as "Meta-y") used for the copy operation.
  3670. # cut -        Name of the key used for the cut operation.
  3671. # paste -    Name of the key used for the paste operation.
  3672.  
  3673. proc tkTextClipboardKeysyms {copy cut paste} {
  3674.     bind Text <$copy> {
  3675.     if {[selection own -displayof %W] == "%W"} {
  3676.         clipboard clear -displayof %W
  3677.         catch {
  3678.         clipboard append -displayof %W [selection get -displayof %W]
  3679.         }
  3680.     }
  3681.     }
  3682.     bind Text <$cut> {
  3683.     if {[selection own -displayof %W] == "%W"} {
  3684.         clipboard clear -displayof %W
  3685.         catch {
  3686.         clipboard append -displayof %W [selection get -displayof %W]
  3687.         %W delete sel.first sel.last
  3688.         }
  3689.     }
  3690.     }
  3691.     bind Text <$paste> {
  3692.     catch {
  3693.         %W insert insert [selection get -displayof %W \
  3694.             -selection CLIPBOARD]
  3695.     }
  3696.     }
  3697. }
  3698.  
  3699. #-------------------------------------------------------------------------
  3700. # The code below creates the default class bindings for entries.
  3701. #-------------------------------------------------------------------------
  3702.  
  3703.     # Standard Motif bindings:
  3704.  
  3705. bind Text <1> {
  3706.     tkTextButton1 %W %x %y
  3707.     %W tag remove sel 0.0 end
  3708. }
  3709. bind Text <B1-Motion> {
  3710.     set tkPriv(x) %x
  3711.     set tkPriv(y) %y
  3712.     tkTextSelectTo %W %x %y
  3713. }
  3714. bind Text <Double-1> {
  3715.     set tkPriv(selectMode) word
  3716.     tkTextSelectTo %W %x %y
  3717.     catch {%W mark set insert sel.first}
  3718. }
  3719. bind Text <Triple-1> {
  3720.     set tkPriv(selectMode) line
  3721.     tkTextSelectTo %W %x %y
  3722.     catch {%W mark set insert sel.first}
  3723. }
  3724. bind Text <Shift-1> {
  3725.     tkTextResetAnchor %W @%x,%y
  3726.     set tkPriv(selectMode) char
  3727.     tkTextSelectTo %W %x %y
  3728. }
  3729. bind Text <Double-Shift-1>    {
  3730.     set tkPriv(selectMode) word
  3731.     tkTextSelectTo %W %x %y
  3732. }
  3733. bind Text <Triple-Shift-1>    {
  3734.     set tkPriv(selectMode) line
  3735.     tkTextSelectTo %W %x %y
  3736. }
  3737. bind Text <B1-Leave> {
  3738.     set tkPriv(x) %x
  3739.     set tkPriv(y) %y
  3740.     tkTextAutoScan %W
  3741. }
  3742. bind Text <B1-Enter> {
  3743.     tkCancelRepeat
  3744. }
  3745. bind Text <ButtonRelease-1> {
  3746.     tkCancelRepeat
  3747. }
  3748. bind Text <Control-1> {
  3749.     %W mark set insert @%x,%y
  3750. }
  3751. bind Text <Left> {
  3752.     tkTextSetCursor %W [%W index {insert - 1c}]
  3753. }
  3754. bind Text <Right> {
  3755.     tkTextSetCursor %W [%W index {insert + 1c}]
  3756. }
  3757. bind Text <Up> {
  3758.     tkTextSetCursor %W [tkTextUpDownLine %W -1]
  3759. }
  3760. bind Text <Down> {
  3761.     tkTextSetCursor %W [tkTextUpDownLine %W 1]
  3762. }
  3763. bind Text <Shift-Left> {
  3764.     tkTextKeySelect %W [%W index {insert - 1c}]
  3765. }
  3766. bind Text <Shift-Right> {
  3767.     tkTextKeySelect %W [%W index {insert + 1c}]
  3768. }
  3769. bind Text <Shift-Up> {
  3770.     tkTextKeySelect %W [tkTextUpDownLine %W -1]
  3771. }
  3772. bind Text <Shift-Down> {
  3773.     tkTextKeySelect %W [tkTextUpDownLine %W 1]
  3774. }
  3775. bind Text <Control-Left> {
  3776.     tkTextSetCursor %W [%W index {insert - 1c wordstart}]
  3777. }
  3778. bind Text <Control-Right> {
  3779.     tkTextSetCursor %W [%W index {insert wordend}]
  3780. }
  3781. bind Text <Control-Up> {
  3782.     tkTextSetCursor %W [tkTextPrevPara %W insert]
  3783. }
  3784. bind Text <Control-Down> {
  3785.     tkTextSetCursor %W [tkTextNextPara %W insert]
  3786. }
  3787. bind Text <Shift-Control-Left> {
  3788.     tkTextKeySelect %W [%W index {insert - 1c wordstart}]
  3789. }
  3790. bind Text <Shift-Control-Right> {
  3791.     tkTextKeySelect %W [%W index {insert wordend}]
  3792. }
  3793. bind Text <Shift-Control-Up> {
  3794.     tkTextKeySelect %W [tkTextPrevPara %W insert]
  3795. }
  3796. bind Text <Shift-Control-Down> {
  3797.     tkTextKeySelect %W [tkTextNextPara %W insert]
  3798. }
  3799. bind Text <Prior> {
  3800.     tkTextSetCursor %W [tkTextScrollPages %W -1]
  3801. }
  3802. bind Text <Shift-Prior> {
  3803.     tkTextKeySelect %W [tkTextScrollPages %W -1]
  3804. }
  3805. bind Text <Next> {
  3806.     tkTextSetCursor %W [tkTextScrollPages %W 1]
  3807. }
  3808. bind Text <Shift-Next> {
  3809.     tkTextKeySelect %W [tkTextScrollPages %W 1]
  3810. }
  3811. bind Text <Control-Prior> {
  3812.     %W xview scroll -1 page
  3813. }
  3814. bind Text <Control-Next> {
  3815.     %W xview scroll 1 page
  3816. }
  3817.  
  3818. bind Text <Home> {
  3819.     tkTextSetCursor %W {insert linestart}
  3820. }
  3821. bind Text <Shift-Home> {
  3822.     tkTextKeySelect %W {insert linestart}
  3823. }
  3824. bind Text <End> {
  3825.     tkTextSetCursor %W {insert lineend}
  3826. }
  3827. bind Text <Shift-End> {
  3828.     tkTextKeySelect %W {insert lineend}
  3829. }
  3830. bind Text <Control-Home> {
  3831.     tkTextSetCursor %W 1.0
  3832. }
  3833. bind Text <Control-Shift-Home> {
  3834.     tkTextKeySelect %W 1.0
  3835. }
  3836. bind Text <Control-End> {
  3837.     tkTextSetCursor %W {end - 1 char}
  3838. }
  3839. bind Text <Control-Shift-End> {
  3840.     tkTextKeySelect %W {end - 1 char}
  3841. }
  3842.  
  3843. bind Text <Tab> {
  3844.     tkTextInsert %W \t
  3845.     focus %W
  3846.     break
  3847. }
  3848. bind Text <Shift-Tab> {
  3849.     # Needed only to keep <Tab> binding from triggering;  doesn't
  3850.     # have to actually do anything.
  3851. }
  3852. bind Text <Control-Tab> {
  3853.     focus [tk_focusNext %W]
  3854. }
  3855. bind Text <Control-Shift-Tab> {
  3856.     focus [tk_focusPrev %W]
  3857. }
  3858. bind Text <Control-i> {
  3859.     tkTextInsert %W \t
  3860. }
  3861. bind Text <Return> {
  3862.     tkTextInsert %W \n
  3863. }
  3864. bind Text <Delete> {
  3865.     if {[%W tag nextrange sel 1.0 end] != ""} {
  3866.     %W delete sel.first sel.last
  3867.     } else {
  3868.     %W delete insert
  3869.     %W see insert
  3870.     }
  3871. }
  3872. bind Text <BackSpace> {
  3873.     if {[%W tag nextrange sel 1.0 end] != ""} {
  3874.     %W delete sel.first sel.last
  3875.     } elseif [%W compare insert != 1.0] {
  3876.     %W delete insert-1c
  3877.     %W see insert
  3878.     }
  3879. }
  3880.  
  3881. bind Text <Control-space> {
  3882.     %W mark set anchor insert
  3883. }
  3884. bind Text <Select> {
  3885.     %W mark set anchor insert
  3886. }
  3887. bind Text <Control-Shift-space> {
  3888.     set tkPriv(selectMode) char
  3889.     tkTextKeyExtend %W insert
  3890. }
  3891. bind Text <Shift-Select> {
  3892.     set tkPriv(selectMode) char
  3893.     tkTextKeyExtend %W insert
  3894. }
  3895. bind Text <Control-slash> {
  3896.     %W tag add sel 1.0 end
  3897. }
  3898. bind Text <Control-backslash> {
  3899.     %W tag remove sel 1.0 end
  3900. }
  3901. tkTextClipboardKeysyms F16 F20 F18
  3902. bind Text <Insert> {
  3903.     catch {tkTextInsert %W [selection get -displayof %W]}
  3904. }
  3905. bind Text <KeyPress> {
  3906.     tkTextInsert %W %A
  3907. }
  3908.  
  3909. # Ignore all Alt, Meta, and Control keypresses unless explicitly bound.
  3910. # Otherwise, if a widget binding for one of these is defined, the
  3911. # <KeyPress> class binding will also fire and insert the character,
  3912. # which is wrong.  Ditto for <Escape>.
  3913.  
  3914. bind Text <Alt-KeyPress> {# nothing }
  3915. bind Text <Meta-KeyPress> {# nothing}
  3916. bind Text <Control-KeyPress> {# nothing}
  3917. bind Text <Escape> {# nothing}
  3918. bind Text <KP_Enter> {# nothing}
  3919.  
  3920. # Additional emacs-like bindings:
  3921.  
  3922. if !$tk_strictMotif {
  3923.     bind Text <Control-a> {
  3924.     tkTextSetCursor %W {insert linestart}
  3925.     }
  3926.     bind Text <Control-b> {
  3927.     tkTextSetCursor %W insert-1c
  3928.     }
  3929.     bind Text <Control-d> {
  3930.     %W delete insert
  3931.     }
  3932.     bind Text <Control-e> {
  3933.     tkTextSetCursor %W {insert lineend}
  3934.     }
  3935.     bind Text <Control-f> {
  3936.     tkTextSetCursor %W insert+1c
  3937.     }
  3938.     bind Text <Control-k> {
  3939.     if [%W compare insert == {insert lineend}] {
  3940.         %W delete insert
  3941.     } else {
  3942.         %W delete insert {insert lineend}
  3943.     }
  3944.     }
  3945.     bind Text <Control-n> {
  3946.     tkTextSetCursor %W [tkTextUpDownLine %W 1]
  3947.     }
  3948.     bind Text <Control-o> {
  3949.     %W insert insert \n
  3950.     %W mark set insert insert-1c
  3951.     }
  3952.     bind Text <Control-p> {
  3953.     tkTextSetCursor %W [tkTextUpDownLine %W -1]
  3954.     }
  3955.     bind Text <Control-t> {
  3956.     tkTextTranspose %W
  3957.     }
  3958.     bind Text <Control-v> {
  3959.     tkTextScrollPages %W 1
  3960.     }
  3961.     bind Text <Meta-b> {
  3962.     tkTextSetCursor %W {insert - 1c wordstart}
  3963.     }
  3964.     bind Text <Meta-d> {
  3965.     %W delete insert {insert wordend}
  3966.     }
  3967.     bind Text <Meta-f> {
  3968.     tkTextSetCursor %W {insert wordend}
  3969.     }
  3970.     bind Text <Meta-less> {
  3971.     tkTextSetCursor %W 1.0
  3972.     }
  3973.     bind Text <Meta-greater> {
  3974.     tkTextSetCursor %W end-1c
  3975.     }
  3976.     bind Text <Meta-BackSpace> {
  3977.     %W delete {insert -1c wordstart} insert
  3978.     }
  3979.     bind Text <Meta-Delete> {
  3980.     %W delete {insert -1c wordstart} insert
  3981.     }
  3982.     tkTextClipboardKeysyms Meta-w Control-w Control-y
  3983.  
  3984.     # A few additional bindings of my own.
  3985.  
  3986.     bind Text <Control-h> {
  3987.     if [%W compare insert != 1.0] {
  3988.         %W delete insert-1c
  3989.         %W see insert
  3990.     }
  3991.     }
  3992.     bind Text <2> {
  3993.     %W scan mark %x %y
  3994.     set tkPriv(x) %x
  3995.     set tkPriv(y) %y
  3996.     set tkPriv(mouseMoved) 0
  3997.     }
  3998.     bind Text <B2-Motion> {
  3999.     if {(%x != $tkPriv(x)) || (%y != $tkPriv(y))} {
  4000.         set tkPriv(mouseMoved) 1
  4001.     }
  4002.     if $tkPriv(mouseMoved) {
  4003.         %W scan dragto %x %y
  4004.     }
  4005.     }
  4006.     bind Text <ButtonRelease-2> {
  4007.     if !$tkPriv(mouseMoved) {
  4008.         catch {
  4009.         %W insert @%x,%y [selection get -displayof %W]
  4010.         }
  4011.     }
  4012.     }
  4013. }
  4014. set tkPriv(prevPos) {}
  4015.  
  4016. # tkTextButton1 --
  4017. # This procedure is invoked to handle button-1 presses in text
  4018. # widgets.  It moves the insertion cursor, sets the selection anchor,
  4019. # and claims the input focus.
  4020. #
  4021. # Arguments:
  4022. # w -        The text window in which the button was pressed.
  4023. # x -        The x-coordinate of the button press.
  4024. # y -        The x-coordinate of the button press.
  4025.  
  4026. proc tkTextButton1 {w x y} {
  4027.     global tkPriv
  4028.  
  4029.     set tkPriv(selectMode) char
  4030.     set tkPriv(mouseMoved) 0
  4031.     set tkPriv(pressX) $x
  4032.     $w mark set insert @$x,$y
  4033.     $w mark set anchor insert
  4034.     if {[$w cget -state] == "normal"} {focus $w}
  4035. }
  4036.  
  4037. # tkTextSelectTo --
  4038. # This procedure is invoked to extend the selection, typically when
  4039. # dragging it with the mouse.  Depending on the selection mode (character,
  4040. # word, line) it selects in different-sized units.  This procedure
  4041. # ignores mouse motions initially until the mouse has moved from
  4042. # one character to another or until there have been multiple clicks.
  4043. #
  4044. # Arguments:
  4045. # w -        The text window in which the button was pressed.
  4046. # x -        Mouse x position.
  4047. # y -         Mouse y position.
  4048.  
  4049. proc tkTextSelectTo {w x y} {
  4050.     global tkPriv
  4051.  
  4052.     set cur [$w index @$x,$y]
  4053.     if [catch {$w index anchor}] {
  4054.     $w mark set anchor $cur
  4055.     }
  4056.     set anchor [$w index anchor]
  4057.     if {[$w compare $cur != $anchor] || (abs($tkPriv(pressX) - $x) >= 3)} {
  4058.     set tkPriv(mouseMoved) 1
  4059.     }
  4060.     switch $tkPriv(selectMode) {
  4061.     char {
  4062.         if [$w compare $cur < anchor] {
  4063.         set first $cur
  4064.         set last anchor
  4065.         } else {
  4066.         set first anchor
  4067.         set last [$w index "$cur + 1c"]
  4068.         }
  4069.     }
  4070.     word {
  4071.         if [$w compare $cur < anchor] {
  4072.         set first [$w index "$cur wordstart"]
  4073.         set last [$w index "anchor - 1c wordend"]
  4074.         } else {
  4075.         set first [$w index "anchor wordstart"]
  4076.         set last [$w index "$cur wordend"]
  4077.         }
  4078.     }
  4079.     line {
  4080.         if [$w compare $cur < anchor] {
  4081.         set first [$w index "$cur linestart"]
  4082.         set last [$w index "anchor - 1c lineend + 1c"]
  4083.         } else {
  4084.         set first [$w index "anchor linestart"]
  4085.         set last [$w index "$cur lineend + 1c"]
  4086.         }
  4087.     }
  4088.     }
  4089.     if {$tkPriv(mouseMoved) || ($tkPriv(selectMode) != "char")} {
  4090.     $w tag remove sel 0.0 $first
  4091.     $w tag add sel $first $last
  4092.     $w tag remove sel $last end
  4093.     update idletasks
  4094.     }
  4095. }
  4096.  
  4097. # tkTextKeyExtend --
  4098. # This procedure handles extending the selection from the keyboard,
  4099. # where the point to extend to is really the boundary between two
  4100. # characters rather than a particular character.
  4101. #
  4102. # Arguments:
  4103. # w -        The text window.
  4104. # index -    The point to which the selection is to be extended.
  4105.  
  4106. proc tkTextKeyExtend {w index} {
  4107.     global tkPriv
  4108.  
  4109.     set cur [$w index $index]
  4110.     if [catch {$w index anchor}] {
  4111.     $w mark set anchor $cur
  4112.     }
  4113.     set anchor [$w index anchor]
  4114.     if [$w compare $cur < anchor] {
  4115.     set first $cur
  4116.     set last anchor
  4117.     } else {
  4118.     set first anchor
  4119.     set last $cur
  4120.     }
  4121.     $w tag remove sel 0.0 $first
  4122.     $w tag add sel $first $last
  4123.     $w tag remove sel $last end
  4124. }
  4125.  
  4126. # tkTextAutoScan --
  4127. # This procedure is invoked when the mouse leaves a text window
  4128. # with button 1 down.  It scrolls the window up, down, left, or right,
  4129. # depending on where the mouse is (this information was saved in
  4130. # tkPriv(x) and tkPriv(y)), and reschedules itself as an "after"
  4131. # command so that the window continues to scroll until the mouse
  4132. # moves back into the window or the mouse button is released.
  4133. #
  4134. # Arguments:
  4135. # w -        The text window.
  4136.  
  4137. proc tkTextAutoScan {w} {
  4138.     global tkPriv
  4139.     if {$tkPriv(y) >= [winfo height $w]} {
  4140.     $w yview scroll 2 units
  4141.     } elseif {$tkPriv(y) < 0} {
  4142.     $w yview scroll -2 units
  4143.     } elseif {$tkPriv(x) >= [winfo width $w]} {
  4144.     $w xview scroll 2 units
  4145.     } elseif {$tkPriv(x) < 0} {
  4146.     $w xview scroll -2 units
  4147.     } else {
  4148.     return
  4149.     }
  4150.     tkTextSelectTo $w $tkPriv(x) $tkPriv(y)
  4151.     set tkPriv(afterId) [after 50 tkTextAutoScan $w]
  4152. }
  4153.  
  4154. # tkTextSetCursor
  4155. # Move the insertion cursor to a given position in a text.  Also
  4156. # clears the selection, if there is one in the text, and makes sure
  4157. # that the insertion cursor is visible.  Also, don't let the insertion
  4158. # cursor appear on the dummy last line of the text.
  4159. #
  4160. # Arguments:
  4161. # w -        The text window.
  4162. # pos -        The desired new position for the cursor in the window.
  4163.  
  4164. proc tkTextSetCursor {w pos} {
  4165.     global tkPriv
  4166.  
  4167.     if [$w compare $pos == end] {
  4168.     set pos {end - 1 chars}
  4169.     }
  4170.     $w mark set insert $pos
  4171.     $w tag remove sel 1.0 end
  4172.     $w see insert
  4173. }
  4174.  
  4175. # tkTextKeySelect
  4176. # This procedure is invoked when stroking out selections using the
  4177. # keyboard.  It moves the cursor to a new position, then extends
  4178. # the selection to that position.
  4179. #
  4180. # Arguments:
  4181. # w -        The text window.
  4182. # new -        A new position for the insertion cursor (the cursor hasn't
  4183. #        actually been moved to this position yet).
  4184.  
  4185. proc tkTextKeySelect {w new} {
  4186.     global tkPriv
  4187.  
  4188.     if {[$w tag nextrange sel 1.0 end] == ""} {
  4189.     if [$w compare $new < insert] {
  4190.         $w tag add sel $new insert
  4191.     } else {
  4192.         $w tag add sel insert $new
  4193.     }
  4194.     $w mark set anchor insert
  4195.     } else {
  4196.     if [$w compare $new < anchor] {
  4197.         set first $new
  4198.         set last anchor
  4199.     } else {
  4200.         set first anchor
  4201.         set last $new
  4202.     }
  4203.     $w tag remove sel 1.0 $first
  4204.     $w tag add sel $first $last
  4205.     $w tag remove sel $last end
  4206.     }
  4207.     $w mark set insert $new
  4208.     $w see insert
  4209.     update idletasks
  4210. }
  4211.  
  4212. # tkTextResetAnchor --
  4213. # Set the selection anchor to whichever end is farthest from the
  4214. # index argument.  One special trick: if the selection has two or
  4215. # fewer characters, just leave the anchor where it is.  In this
  4216. # case it doesn't matter which point gets chosen for the anchor,
  4217. # and for the things like Shift-Left and Shift-Right this produces
  4218. # better behavior when the cursor moves back and forth across the
  4219. # anchor.
  4220. #
  4221. # Arguments:
  4222. # w -        The text widget.
  4223. # index -    Position at which mouse button was pressed, which determines
  4224. #        which end of selection should be used as anchor point.
  4225.  
  4226. proc tkTextResetAnchor {w index} {
  4227.     global tkPriv
  4228.  
  4229.     if {[$w tag ranges sel] == ""} {
  4230.     $w mark set anchor $index
  4231.     return
  4232.     }
  4233.     set a [$w index $index]
  4234.     set b [$w index sel.first]
  4235.     set c [$w index sel.last]
  4236.     if [$w compare $a < $b] {
  4237.     $w mark set anchor sel.last
  4238.     return
  4239.     }
  4240.     if [$w compare $a > $c] {
  4241.     $w mark set anchor sel.first
  4242.     return
  4243.     }
  4244.     scan $a "%d.%d" lineA chA
  4245.     scan $b "%d.%d" lineB chB
  4246.     scan $c "%d.%d" lineC chC
  4247.     if {$lineB < $lineC+2} {
  4248.     set total [string length [$w get $b $c]]
  4249.     if {$total <= 2} {
  4250.         return
  4251.     }
  4252.     if {[string length [$w get $b $a]] < ($total/2)} {
  4253.         $w mark set anchor sel.last
  4254.     } else {
  4255.         $w mark set anchor sel.first
  4256.     }
  4257.     return
  4258.     }
  4259.     if {($lineA-$lineB) < ($lineC-$lineA)} {
  4260.     $w mark set anchor sel.last
  4261.     } else {
  4262.     $w mark set anchor sel.first
  4263.     }
  4264. }
  4265.  
  4266. # tkTextInsert --
  4267. # Insert a string into a text at the point of the insertion cursor.
  4268. # If there is a selection in the text, and it covers the point of the
  4269. # insertion cursor, then delete the selection before inserting.
  4270. #
  4271. # Arguments:
  4272. # w -        The text window in which to insert the string
  4273. # s -        The string to insert (usually just a single character)
  4274.  
  4275. proc tkTextInsert {w s} {
  4276.     if {($s == "") || ([$w cget -state] == "disabled")} {
  4277.     return
  4278.     }
  4279.     catch {
  4280.     if {[$w compare sel.first <= insert]
  4281.         && [$w compare sel.last >= insert]} {
  4282.         $w delete sel.first sel.last
  4283.     }
  4284.     }
  4285.     $w insert insert $s
  4286.     $w see insert
  4287. }
  4288.  
  4289. # tkTextUpDownLine --
  4290. # Returns the index of the character one line above or below the
  4291. # insertion cursor.  There are two tricky things here.  First,
  4292. # we want to maintain the original column across repeated operations,
  4293. # even though some lines that will get passed through don't have
  4294. # enough characters to cover the original column.  Second, don't
  4295. # try to scroll past the beginning or end of the text.
  4296. #
  4297. # Arguments:
  4298. # w -        The text window in which the cursor is to move.
  4299. # n -        The number of lines to move: -1 for up one line,
  4300. #        +1 for down one line.
  4301.  
  4302. proc tkTextUpDownLine {w n} {
  4303.     global tkPriv
  4304.  
  4305.     set i [$w index insert]
  4306.     scan $i "%d.%d" line char
  4307.     if {[string compare $tkPriv(prevPos) $i] != 0} {
  4308.     set tkPriv(char) $char
  4309.     }
  4310.     set new [$w index [expr $line + $n].$tkPriv(char)]
  4311.     if {[$w compare $new == end] || [$w compare $new == "insert linestart"]} {
  4312.     set new $i
  4313.     }
  4314.     set tkPriv(prevPos) $new
  4315.     return $new
  4316. }
  4317.  
  4318. # tkTextPrevPara --
  4319. # Returns the index of the beginning of the paragraph just before a given
  4320. # position in the text (the beginning of a paragraph is the first non-blank
  4321. # character after a blank line).
  4322. #
  4323. # Arguments:
  4324. # w -        The text window in which the cursor is to move.
  4325. # pos -        Position at which to start search.
  4326.  
  4327. proc tkTextPrevPara {w pos} {
  4328.     set pos [$w index "$pos linestart"]
  4329.     while 1 {
  4330.     if {(([$w get "$pos - 1 line"] == "\n") && ([$w get $pos] != "\n"))
  4331.         || ($pos == "1.0")} {
  4332.         if [regexp -indices {^[     ]+(.)} [$w get $pos "$pos lineend"] \
  4333.             dummy index] {
  4334.         set pos [$w index "$pos + [lindex $index 0] chars"]
  4335.         }
  4336.         if {[$w compare $pos != insert] || ($pos == "1.0")} {
  4337.         return $pos
  4338.         }
  4339.     }
  4340.     set pos [$w index "$pos - 1 line"]
  4341.     }
  4342. }
  4343.  
  4344. # tkTextNextPara --
  4345. # Returns the index of the beginning of the paragraph just after a given
  4346. # position in the text (the beginning of a paragraph is the first non-blank
  4347. # character after a blank line).
  4348. #
  4349. # Arguments:
  4350. # w -        The text window in which the cursor is to move.
  4351. # start -    Position at which to start search.
  4352.  
  4353. proc tkTextNextPara {w start} {
  4354.     set pos [$w index "$start linestart + 1 line"]
  4355.     while {[$w get $pos] != "\n"} {
  4356.     if [$w compare $pos == end] {
  4357.         return [$w index "end - 1c"]
  4358.     }
  4359.     set pos [$w index "$pos + 1 line"]
  4360.     }
  4361.     while {[$w get $pos] == "\n"} {
  4362.     set pos [$w index "$pos + 1 line"]
  4363.     if [$w compare $pos == end] {
  4364.         return [$w index "end - 1c"]
  4365.     }
  4366.     }
  4367.     if [regexp -indices {^[     ]+(.)} [$w get $pos "$pos lineend"] \
  4368.         dummy index] {
  4369.     return [$w index "$pos + [lindex $index 0] chars"]
  4370.     }
  4371.     return $pos
  4372. }
  4373.  
  4374. # tkTextScrollPages --
  4375. # This is a utility procedure used in bindings for moving up and down
  4376. # pages and possibly extending the selection along the way.  It scrolls
  4377. # the view in the widget by the number of pages, and it returns the
  4378. # index of the character that is at the same position in the new view
  4379. # as the insertion cursor used to be in the old view.
  4380. #
  4381. # Arguments:
  4382. # w -        The text window in which the cursor is to move.
  4383. # count -    Number of pages forward to scroll;  may be negative
  4384. #        to scroll backwards.
  4385.  
  4386. proc tkTextScrollPages {w count} {
  4387.     set bbox [$w bbox insert]
  4388.     $w yview scroll $count pages
  4389.     if {$bbox == ""} {
  4390.     return [$w index @[expr [winfo height $w]/2],0]
  4391.     }
  4392.     return [$w index @[lindex $bbox 0],[lindex $bbox 1]]
  4393. }
  4394.  
  4395. # tkTextTranspose --
  4396. # This procedure implements the "transpose" function for text widgets.
  4397. # It tranposes the characters on either side of the insertion cursor,
  4398. # unless the cursor is at the end of the line.  In this case it
  4399. # transposes the two characters to the left of the cursor.  In either
  4400. # case, the cursor ends up to the right of the transposed characters.
  4401. #
  4402. # Arguments:
  4403. # w -        Text window in which to transpose.
  4404.  
  4405. proc tkTextTranspose w {
  4406.     set pos insert
  4407.     if [$w compare $pos != "$pos lineend"] {
  4408.     set pos [$w index "$pos + 1 char"]
  4409.     }
  4410.     set new [$w get "$pos - 1 char"][$w get  "$pos - 2 char"]
  4411.     if [$w compare "$pos - 1 char" == 1.0] {
  4412.     return
  4413.     }
  4414.     $w delete "$pos - 2 char" $pos
  4415.     $w insert insert $new
  4416.     $w see insert
  4417. }
  4418. #@package: library/palette tk_setPalette tkRecolorTree tkDarken tk_bisque
  4419.  
  4420. # palette.tcl --
  4421. #
  4422. # This file contains procedures that change the color palette used
  4423. # by Tk.
  4424. #
  4425. # @(#) palette.tcl 1.1 95/05/22 14:55:29
  4426. #
  4427. # Copyright (c) 1995 Sun Microsystems, Inc.
  4428. #
  4429. # See the file "license.terms" for information on usage and redistribution
  4430. # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  4431. #
  4432.  
  4433. # tk_setPalette --
  4434. # Changes the default color scheme for a Tk application by setting
  4435. # default colors in the option database and by modifying all of the
  4436. # color options for existing widgets that have the default value.
  4437. #
  4438. # Arguments:
  4439. # The arguments consist of either a single color name, which
  4440. # will be used as the new background color (all other colors will
  4441. # be computed from this) or an even number of values consisting of
  4442. # option names and values.  The name for an option is the one used
  4443. # for the option database, such as activeForeground, not -activeforeground.
  4444.  
  4445. proc tk_setPalette args {
  4446.     global tkPalette
  4447.  
  4448.     # Create an array that has the complete new palette.  If some colors
  4449.     # aren't specified, compute them from other colors that are specified.
  4450.  
  4451.     if {[llength $args] == 1} {
  4452.     set new(background) [lindex $args 0]
  4453.     } else {
  4454.     array set new $args
  4455.     }
  4456.     if ![info exists new(background)] {
  4457.     error "must specify a background color"
  4458.     }
  4459.     if ![info exists new(foreground)] {
  4460.     set new(foreground) black
  4461.     }
  4462.     set bg [winfo rgb . $new(background)]
  4463.     set fg [winfo rgb . $new(foreground)]
  4464.     set darkerBg [format #%02x%02x%02x [expr (9*[lindex $bg 0])/2560] \
  4465.         [expr (9*[lindex $bg 1])/2560] [expr (9*[lindex $bg 2])/2560]]
  4466.     foreach i {activeForeground insertBackground selectForeground \
  4467.         highlightColor} {
  4468.     if ![info exists new($i)] {
  4469.         set new($i) $new(foreground)
  4470.     }
  4471.     }
  4472.     if ![info exists new(disabledForeground)] {
  4473.     set new(disabledForeground) [format #%02x%02x%02x \
  4474.         [expr (3*[lindex $bg 0] + [lindex $fg 0])/1024] \
  4475.         [expr (3*[lindex $bg 1] + [lindex $fg 1])/1024] \
  4476.         [expr (3*[lindex $bg 2] + [lindex $fg 2])/1024]]
  4477.     }
  4478.     if ![info exists new(highlightBackground)] {
  4479.     set new(highlightBackground) $new(background)
  4480.     }
  4481.     if ![info exists new(activeBackground)] {
  4482.     # Pick a default active background that islighter than the
  4483.     # normal background.  To do this, round each color component
  4484.     # up by 15% or 1/3 of the way to full white, whichever is
  4485.     # greater.
  4486.  
  4487.     foreach i {0 1 2} {
  4488.         set light($i) [expr [lindex $bg $i]/256]
  4489.         set inc1 [expr ($light($i)*15)/100]
  4490.         set inc2 [expr (255-$light($i))/3]
  4491.         if {$inc1 > $inc2} {
  4492.         incr light($i) $inc1
  4493.         } else {
  4494.         incr light($i) $inc2
  4495.         }
  4496.         if {$light($i) > 255} {
  4497.         set light($i) 255
  4498.         }
  4499.     }
  4500.     set new(activeBackground) [format #%02x%02x%02x $light(0) \
  4501.         $light(1) $light(2)]
  4502.     }
  4503.     if ![info exists new(selectBackground)] {
  4504.     set new(selectBackground) $darkerBg
  4505.     }
  4506.     if ![info exists new(troughColor)] {
  4507.     set new(troughColor) $darkerBg
  4508.     }
  4509.     if ![info exists new(selectColor)] {
  4510.     set new(selectColor) #b03060
  4511.     }
  4512.  
  4513.     # Walk the widget hierarchy, recoloring all existing windows.
  4514.     # Before doing this, make sure that the tkPalette variable holds
  4515.     # the default values of all options, so that tkRecolorTree can
  4516.     # be sure to only change options that have their default values.
  4517.     # If the variable exists, then it is already correct (it was created
  4518.     # the last time this procedure was invoked).  If the variable
  4519.     # doesn't exist, fill it in using the defaults from a few widgets.
  4520.  
  4521.     if ![info exists tkPalette] {
  4522.     checkbutton .c14732
  4523.     entry .e14732
  4524.     scrollbar .s14732
  4525.     set tkPalette(activeBackground) \
  4526.         [lindex [.c14732 configure -activebackground] 3]
  4527.     set tkPalette(activeForeground) \
  4528.         [lindex [.c14732 configure -activeforeground] 3]
  4529.     set tkPalette(background) \
  4530.         [lindex [.c14732 configure -background] 3]
  4531.     set tkPalette(disabledForeground) \
  4532.         [lindex [.c14732 configure -disabledforeground] 3]
  4533.     set tkPalette(foreground) \
  4534.         [lindex [.c14732 configure -foreground] 3]
  4535.     set tkPalette(highlightBackground) \
  4536.         [lindex [.c14732 configure -highlightbackground] 3]
  4537.     set tkPalette(highlightColor) \
  4538.         [lindex [.c14732 configure -highlightcolor] 3]
  4539.     set tkPalette(insertBackground) \
  4540.         [lindex [.e14732 configure -insertbackground] 3]
  4541.     set tkPalette(selectColor) \
  4542.         [lindex [.c14732 configure -selectcolor] 3]
  4543.     set tkPalette(selectBackground) \
  4544.         [lindex [.e14732 configure -selectbackground] 3]
  4545.     set tkPalette(selectForeground) \
  4546.         [lindex [.e14732 configure -selectforeground] 3]
  4547.     set tkPalette(troughColor) \
  4548.         [lindex [.s14732 configure -troughcolor] 3]
  4549.     destroy .c14732 .e14732 .s14732
  4550.     }
  4551.     tkRecolorTree . new
  4552.  
  4553.     # Change the option database so that future windows will get the
  4554.     # same colors.
  4555.  
  4556.     foreach option [array names new] {
  4557.     option add *$option $new($option) widgetDefault
  4558.     }
  4559.  
  4560.     # Save the options in the global variable tkPalette, for use the
  4561.     # next time we change the options.
  4562.  
  4563.     array set tkPalette [array get new]
  4564. }
  4565.  
  4566. # tkRecolorTree --
  4567. # This procedure changes the colors in a window and all of its
  4568. # descendants, according to information provided by the colors
  4569. # argument.  It only modifies colors that have their default values
  4570. # as specified by the tkPalette variable.
  4571. #
  4572. # Arguments:
  4573. # w -            The name of a window.  This window and all its
  4574. #            descendants are recolored.
  4575. # colors -        The name of an array variable in the caller,
  4576. #            which contains color information.  Each element
  4577. #            is named after a widget configuration option, and
  4578. #            each value is the value for that option.
  4579.  
  4580. proc tkRecolorTree {w colors} {
  4581.     global tkPalette
  4582.     upvar $colors c
  4583.     foreach dbOption [array names c] {
  4584.     set option -[string tolower $dbOption]
  4585.     if ![catch {$w cget $option} value] {
  4586.         if {$value == $tkPalette($dbOption)} {
  4587.         $w configure $option $c($dbOption)
  4588.         }
  4589.     }
  4590.     }
  4591.     foreach child [winfo children $w] {
  4592.     tkRecolorTree $child c
  4593.     }
  4594. }
  4595.  
  4596. # tkDarken --
  4597. # Given a color name, computes a new color value that darkens (or
  4598. # brightens) the given color by a given percent.
  4599. #
  4600. # Arguments:
  4601. # color -    Name of starting color.
  4602. # perecent -    Integer telling how much to brighten or darken as a
  4603. #        percent: 50 means darken by 50%, 110 means brighten
  4604. #        by 10%.
  4605.  
  4606. proc tkDarken {color percent} {
  4607.     set l [winfo rgb . $color]
  4608.     set red [expr [lindex $l 0]/256]
  4609.     set green [expr [lindex $l 1]/256]
  4610.     set blue [expr [lindex $l 2]/256]
  4611.     set red [expr ($red*$percent)/100]
  4612.     if {$red > 255} {
  4613.     set red 255
  4614.     }
  4615.     set green [expr ($green*$percent)/100]
  4616.     if {$green > 255} {
  4617.     set green 255
  4618.     }
  4619.     set blue [expr ($blue*$percent)/100]
  4620.     if {$blue > 255} {
  4621.     set blue 255
  4622.     }
  4623.     format #%02x%02x%02x $red $green $blue
  4624. }
  4625.  
  4626. # tk_bisque --
  4627. # Reset the Tk color palette to the old "bisque" colors.
  4628. #
  4629. # Arguments:
  4630. # None.
  4631.  
  4632. proc tk_bisque {} {
  4633.     tk_setPalette activeBackground #e6ceb1 activeForeground black \
  4634.         background #ffe4c4 disabledForeground #b0b0b0 foreground black \
  4635.         highlightBackground #ffe4c4 highlightColor black \
  4636.         insertBackground black selectColor #b03060 \
  4637.         selectBackground #e6ceb1 selectForeground black \
  4638.         troughColor #cdb79e
  4639. }
  4640. #@package: library/tearoff tkMenuDup tkTearOffMenu
  4641.  
  4642. # tearoff.tcl --
  4643. #
  4644. # This file contains procedures that implement tear-off menus.
  4645. #
  4646. # @(#) tearoff.tcl 1.7 95/08/30 09:11:52
  4647. #
  4648. # Copyright (c) 1994 The Regents of the University of California.
  4649. # Copyright (c) 1994-1995 Sun Microsystems, Inc.
  4650. #
  4651. # See the file "license.terms" for information on usage and redistribution
  4652. # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  4653. #
  4654.  
  4655. # tkTearoffMenu --
  4656. # Given the name of a menu, this procedure creates a torn-off menu
  4657. # that is identical to the given menu (including nested submenus).
  4658. # The new torn-off menu exists as a toplevel window managed by the
  4659. # window manager.  The return value is the name of the new menu.
  4660. #
  4661. # Arguments:
  4662. # w -            The menu to be torn-off (duplicated).
  4663.  
  4664. proc tkTearOffMenu w {
  4665.     # Find a unique name to use for the torn-off menu.  Find the first
  4666.     # ancestor of w that is a toplevel but not a menu, and use this as
  4667.     # the parent of the new menu.  This guarantees that the torn off
  4668.     # menu will be on the same screen as the original menu.  By making
  4669.     # it a child of the ancestor, rather than a child of the menu, it
  4670.     # can continue to live even if the menu is deleted;  it will go
  4671.     # away when the toplevel goes away.
  4672.  
  4673.     set parent [winfo parent $w]
  4674.     while {([winfo toplevel $parent] != $parent)
  4675.         || ([winfo class $parent] == "Menu")} {
  4676.     set parent [winfo parent $parent]
  4677.     }
  4678.     if {$parent == "."} {
  4679.     set parent ""
  4680.     }
  4681.     for {set i 1} 1 {incr i} {
  4682.     set menu $parent.tearoff$i
  4683.     if ![winfo exists $menu] {
  4684.         break
  4685.     }
  4686.     }
  4687.  
  4688.     tkMenuDup $w $menu
  4689.     $menu configure -transient 0
  4690.  
  4691.     # Pick a title for the new menu by looking at the parent of the
  4692.     # original: if the parent is a menu, then use the text of the active
  4693.     # entry.  If it's a menubutton then use its text.
  4694.  
  4695.     set parent [winfo parent $w]
  4696.     switch [winfo class $parent] {
  4697.     Menubutton {
  4698.         wm title $menu [$parent cget -text]
  4699.     }
  4700.     Menu {
  4701.         wm title $menu [$parent entrycget active -label]
  4702.     }
  4703.     }
  4704.  
  4705.     $menu configure -tearoff 0
  4706.     $menu post [winfo x $w] [winfo y $w]
  4707.  
  4708.     # Set tkPriv(focus) on entry:  otherwise the focus will get lost
  4709.     # after keyboard invocation of a sub-menu (it will stay on the
  4710.     # submenu).
  4711.  
  4712.     bind $menu <Enter> {
  4713.     set tkPriv(focus) %W
  4714.     }
  4715.  
  4716.     # If there is a -tearoffcommand option for the menu, invoke it
  4717.     # now.
  4718.  
  4719.     set cmd [$w cget -tearoffcommand]
  4720.     if {$cmd != ""} {
  4721.     eval $cmd $w $menu
  4722.     }
  4723. }
  4724.  
  4725. # tkMenuDup --
  4726. # Given a menu (hierarchy), create a duplicate menu (hierarchy)
  4727. # in a given window.
  4728. #
  4729. # Arguments:
  4730. # src -            Source window.  Must be a menu.  It and its
  4731. #            menu descendants will be duplicated at dst.
  4732. # dst -            Name to use for topmost menu in duplicate
  4733. #            hierarchy.
  4734.  
  4735. proc tkMenuDup {src dst} {
  4736.     set cmd "menu $dst"
  4737.     foreach option [$src configure] {
  4738.     if {[llength $option] == 2} {
  4739.         continue
  4740.     }
  4741.     lappend cmd [lindex $option 0] [lindex $option 4]
  4742.     }
  4743.     eval $cmd
  4744.     set last [$src index last]
  4745.     if {$last == "none"} {
  4746.     return
  4747.     }
  4748.     for {set i [$src cget -tearoff]} {$i <= $last} {incr i} {
  4749.     set cmd "$dst add [$src type $i]"
  4750.     foreach option [$src entryconfigure $i]  {
  4751.         lappend cmd [lindex $option 0] [lindex $option 4]
  4752.     }
  4753.     eval $cmd
  4754.     if {[$src type $i] == "cascade"} {
  4755.         tkMenuDup [$src entrycget $i -menu] $dst.m$i
  4756.         $dst entryconfigure $i -menu $dst.m$i
  4757.     }
  4758.     }
  4759.  
  4760.     # Duplicate the binding tags and bindings from the source menu.
  4761.  
  4762.     regsub -all . $src {\\&} quotedSrc
  4763.     regsub -all . $dst {\\&} quotedDst
  4764.     regsub -all $quotedSrc [bindtags $src] $dst x
  4765.     bindtags $dst $x
  4766.     foreach event [bind $src] {
  4767.     regsub -all $quotedSrc [bind $src $event] $dst x
  4768.     bind $dst $event $x
  4769.     }
  4770. }
  4771. #
  4772. # tkdemo --
  4773. #
  4774. # Run the Tk demo at anytime after Extended Tcl is installed.
  4775. #------------------------------------------------------------------------------
  4776. # Copyright 1992-1995 Karl Lehenbauer and Mark Diekhans.
  4777. #
  4778. # Permission to use, copy, modify, and distribute this software and its
  4779. # documentation for any purpose and without fee is hereby granted, provided
  4780. # that the above copyright notice appear in all copies.  Karl Lehenbauer and
  4781. # Mark Diekhans make no representations about the suitability of this
  4782. # software for any purpose.  It is provided "as is" without express or
  4783. # implied warranty.
  4784. #------------------------------------------------------------------------------
  4785. # $Id: tkdemo.tcl,v 5.0 1995/07/25 06:00:33 markd Rel $
  4786. #------------------------------------------------------------------------------
  4787. #
  4788.  
  4789. #@package: Tk-demo tkdemo
  4790.  
  4791. proc tkdemo {} {
  4792.     global auto_path
  4793.     if {[info commands tkwait] == ""} {
  4794.         error "tkdemo may only be used from wishx"
  4795.     }
  4796.     set demos [searchpath $auto_path demos]
  4797.     if {$demos == "" || ![file isdirectory $demos]} {
  4798.         error "can't find Tk `demos' directory on the auto_path (auto_path)"
  4799.     }
  4800.     uplevel #0 source $demos/widget
  4801. }
  4802.  
  4803.  
  4804.